From 5e5b236ef84e7a6d75e349ebb1907da2436f3010 Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Tue, 22 Dec 2020 11:33:24 +0300 Subject: [PATCH] Extract record related parts into smaller bunch files for 201 --- .../codegen/VersionIndependentOpcodes.kt | 13 + .../codegen/VersionIndependentOpcodes.kt.201 | 13 + .../kotlin/codegen/ClassBuilderRecord.kt | 10 + .../kotlin/codegen/ClassBuilderRecord.kt.201 | 10 + .../codegen/ImplementationBodyCodegen.java | 2 +- .../ImplementationBodyCodegen.java.201 | 1248 ----------------- .../kotlin/codegen/PropertyCodegen.java | 2 +- .../kotlin/codegen/PropertyCodegen.java.201 | 680 --------- .../cli/jvm/compiler/JavaLanguageLevel.kt | 14 + .../cli/jvm/compiler/JavaLanguageLevel.kt.201 | 14 + .../cli/jvm/compiler/KotlinCoreEnvironment.kt | 2 +- .../jvm/compiler/KotlinCoreEnvironment.kt.201 | 703 ---------- .../backend/jvm/codegen/ClassCodegen.kt | 7 +- .../backend/jvm/codegen/ClassCodegen.kt.201 | 495 ------- 14 files changed, 80 insertions(+), 3133 deletions(-) create mode 100644 compiler/backend.common.jvm/src/org/jetbrains/kotlin/codegen/VersionIndependentOpcodes.kt create mode 100644 compiler/backend.common.jvm/src/org/jetbrains/kotlin/codegen/VersionIndependentOpcodes.kt.201 create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt.201 delete mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java.201 delete mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java.201 create mode 100644 compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JavaLanguageLevel.kt create mode 100644 compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JavaLanguageLevel.kt.201 delete mode 100644 compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt.201 delete mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt.201 diff --git a/compiler/backend.common.jvm/src/org/jetbrains/kotlin/codegen/VersionIndependentOpcodes.kt b/compiler/backend.common.jvm/src/org/jetbrains/kotlin/codegen/VersionIndependentOpcodes.kt new file mode 100644 index 00000000000..8c4d80e2a62 --- /dev/null +++ b/compiler/backend.common.jvm/src/org/jetbrains/kotlin/codegen/VersionIndependentOpcodes.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.codegen + +import org.jetbrains.org.objectweb.asm.Opcodes + +// This object should help compiling against different ASM versions in different bunch versions +object VersionIndependentOpcodes { + const val ACC_RECORD = Opcodes.ACC_RECORD +} diff --git a/compiler/backend.common.jvm/src/org/jetbrains/kotlin/codegen/VersionIndependentOpcodes.kt.201 b/compiler/backend.common.jvm/src/org/jetbrains/kotlin/codegen/VersionIndependentOpcodes.kt.201 new file mode 100644 index 00000000000..2b2b7422592 --- /dev/null +++ b/compiler/backend.common.jvm/src/org/jetbrains/kotlin/codegen/VersionIndependentOpcodes.kt.201 @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.codegen + +import org.jetbrains.org.objectweb.asm.Opcodes + +// This object should help compiling against different ASM versions from different bunch versions +object VersionIndependentOpcodes { + const val ACC_RECORD = 0 +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt new file mode 100644 index 00000000000..eaf3adc8077 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.codegen + +fun ClassBuilder.addRecordComponent(name: String, desc: String, signature: String?) { + newRecordComponent(name, desc, signature) +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt.201 b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt.201 new file mode 100644 index 00000000000..72d66859291 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassBuilderRecord.kt.201 @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.codegen + +fun ClassBuilder.addRecordComponent(name: String, desc: String, signature: String?) { + // newRecordComponent(name, desc, signature) +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index caa9fedb583..a7063ee9de6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -223,7 +223,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } if (JvmAnnotationUtilKt.isJvmRecord(descriptor)) { - access |= ACC_RECORD; + access |= VersionIndependentOpcodes.ACC_RECORD; } v.defineClass( diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java.201 b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java.201 deleted file mode 100644 index f2c8aa9d96d..00000000000 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java.201 +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.codegen; - -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.psi.PsiElement; -import com.intellij.util.ArrayUtil; -import kotlin.Unit; -import kotlin.collections.CollectionsKt; -import kotlin.jvm.functions.Function2; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.backend.common.DataClassMethodGenerator; -import org.jetbrains.kotlin.builtins.KotlinBuiltIns; -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap; -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap.PlatformMutabilityMapping; -import org.jetbrains.kotlin.codegen.binding.CodegenBinding; -import org.jetbrains.kotlin.codegen.binding.MutableClosure; -import org.jetbrains.kotlin.codegen.context.*; -import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; -import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension; -import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; -import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; -import org.jetbrains.kotlin.codegen.state.GenerationState; -import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; -import org.jetbrains.kotlin.config.LanguageFeature; -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.incremental.components.NoLookupLocation; -import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; -import org.jetbrains.kotlin.load.kotlin.TypeMappingMode; -import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader; -import org.jetbrains.kotlin.metadata.ProtoBuf; -import org.jetbrains.kotlin.name.ClassId; -import org.jetbrains.kotlin.name.FqName; -import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor; -import org.jetbrains.kotlin.resolve.*; -import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; -import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; -import org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt; -import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; -import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter; -import org.jetbrains.kotlin.resolve.scopes.MemberScope; -import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver; -import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver; -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.kotlin.serialization.DescriptorSerializer; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.org.objectweb.asm.FieldVisitor; -import org.jetbrains.org.objectweb.asm.MethodVisitor; -import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; -import org.jetbrains.org.objectweb.asm.commons.Method; - -import java.util.*; - -import static org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUES; -import static org.jetbrains.kotlin.builtins.StandardNames.ENUM_VALUE_OF; -import static org.jetbrains.kotlin.codegen.AsmUtil.CAPTURED_THIS_FIELD; -import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isGenericToArray; -import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isNonGenericToArray; -import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.*; -import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*; -import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass; -import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.getDelegatedLocalVariableMetadata; -import static org.jetbrains.kotlin.load.java.DescriptorsJvmAbiUtil.*; -import static org.jetbrains.kotlin.load.java.JvmAbi.HIDDEN_INSTANCE_FIELD; -import static org.jetbrains.kotlin.load.java.JvmAbi.INSTANCE_FIELD; -import static org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_GET; -import static org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_SET; -import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull; -import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration; -import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; -import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; -import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; -import static org.jetbrains.kotlin.types.Variance.INVARIANT; -import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isLocalFunction; -import static org.jetbrains.org.objectweb.asm.Opcodes.*; -import static org.jetbrains.org.objectweb.asm.Type.getObjectType; - -public class ImplementationBodyCodegen extends ClassBodyCodegen { - public static final String ENUM_VALUES_FIELD_NAME = "$VALUES"; - private Type superClassAsmType; - @NotNull - private SuperClassInfo superClassInfo; - private final Type classAsmType; - private final boolean isLocal; - - private List companionObjectPropertiesToCopy; - - private final DelegationFieldsInfo delegationFieldsInfo; - - private final List> additionalTasks = new ArrayList<>(); - - private final DescriptorSerializer serializer; - - private final ConstructorCodegen constructorCodegen; - - public ImplementationBodyCodegen( - @NotNull KtPureClassOrObject aClass, - @NotNull ClassContext context, - @NotNull ClassBuilder v, - @NotNull GenerationState state, - @Nullable MemberCodegen parentCodegen, - boolean isLocal - ) { - super(aClass, context, v, state, parentCodegen); - this.classAsmType = getObjectType(typeMapper.classInternalName(descriptor)); - this.isLocal = isLocal; - - this.delegationFieldsInfo = - new DelegationFieldsInfo(classAsmType, descriptor, state, bindingContext) - .getDelegationFieldsInfo(myClass.getSuperTypeListEntries()); - - JvmSerializerExtension extension = new JvmSerializerExtension(v.getSerializationBindings(), state); - this.serializer = DescriptorSerializer.create( - descriptor, extension, - parentCodegen instanceof ImplementationBodyCodegen - ? ((ImplementationBodyCodegen) parentCodegen).serializer - : DescriptorSerializer.createTopLevel(extension), - state.getProject() - ); - - this.constructorCodegen = new ConstructorCodegen( - descriptor, context, functionCodegen, this, - this, state, kind, v, classAsmType, myClass, bindingContext - ); - } - - @Override - protected void generateDeclaration() { - superClassInfo = SuperClassInfo.getSuperClassInfo(descriptor, typeMapper); - superClassAsmType = superClassInfo.getType(); - - JvmClassSignature signature = signature(); - - boolean isAbstract = false; - boolean isInterface = false; - boolean isFinal = false; - boolean isAnnotation = false; - boolean isEnum = false; - - ClassKind kind = descriptor.getKind(); - - Modality modality = descriptor.getModality(); - - if (modality == Modality.ABSTRACT || modality == Modality.SEALED) { - isAbstract = true; - } - - if (kind == ClassKind.INTERFACE) { - isAbstract = true; - isInterface = true; - } - else if (kind == ClassKind.ANNOTATION_CLASS) { - isAbstract = true; - isInterface = true; - isAnnotation = true; - } - else if (kind == ClassKind.ENUM_CLASS) { - isAbstract = hasAbstractMembers(descriptor); - isEnum = true; - } - - if (modality != Modality.OPEN && !isAbstract) { - isFinal = kind == ClassKind.OBJECT || - // Light-class mode: Do not make enum classes final since PsiClass corresponding to enum is expected to be inheritable from - !(kind == ClassKind.ENUM_CLASS && !state.getClassBuilderMode().generateBodies); - } - - int access = 0; - - if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES && !DescriptorUtils.isTopLevelDeclaration(descriptor)) { - // !ClassBuilderMode.generateBodies means we are generating light classes & looking at a nested or inner class - // Light class generation is implemented so that Cls-classes only read bare code of classes, - // without knowing whether these classes are inner or not (see ClassStubBuilder.EMPTY_STRATEGY) - // Thus we must write full accessibility flags on inner classes in this mode - access |= getVisibilityAccessFlag(descriptor); - // Same for STATIC - if (!descriptor.isInner()) { - access |= ACC_STATIC; - } - } - else { - access |= getVisibilityAccessFlagForClass(descriptor); - } - if (isAbstract) { - access |= ACC_ABSTRACT; - } - if (isInterface) { - access |= ACC_INTERFACE; // ACC_SUPER - } - else { - access |= ACC_SUPER; - } - if (isFinal) { - access |= ACC_FINAL; - } - if (isAnnotation) { - access |= ACC_ANNOTATION; - } - if (KotlinBuiltIns.isDeprecated(descriptor)) { - access |= ACC_DEPRECATED; - } - if (isEnum) { - for (KtDeclaration declaration : myClass.getDeclarations()) { - if (declaration instanceof KtEnumEntry) { - if (enumEntryNeedSubclass(bindingContext, (KtEnumEntry) declaration)) { - access &= ~ACC_FINAL; - } - } - } - access |= ACC_ENUM; - } - - v.defineClass( - myClass.getPsiOrParent(), - state.getClassFileVersion(), - access, - signature.getName(), - signature.getJavaGenericSignature(), - signature.getSuperclassName(), - ArrayUtil.toStringArray(signature.getInterfaces()) - ); - - v.visitSource(myClass.getContainingKtFile().getName(), null); - - initDefaultSourceMappingIfNeeded(); - - writeEnclosingMethod(); - - AnnotationCodegen.forClass(v.getVisitor(), this, state).genAnnotations(descriptor, null, null); - - generateEnumEntries(); - } - - @Override - protected void generateDefaultImplsIfNeeded() { - if (isInterface(descriptor) && !isLocal) { - Type defaultImplsType = state.getTypeMapper().mapDefaultImpls(descriptor); - ClassBuilder defaultImplsBuilder = - state.getFactory().newVisitor(JvmDeclarationOriginKt.DefaultImpls(myClass.getPsiOrParent(), descriptor), defaultImplsType, myClass.getContainingKtFile()); - - CodegenContext parentContext = context.getParentContext(); - assert parentContext != null : "Parent context of interface declaration should not be null"; - - ClassContext defaultImplsContext = parentContext.intoDefaultImplsClass(descriptor, (ClassContext) context, state); - new InterfaceImplBodyCodegen(myClass, defaultImplsContext, defaultImplsBuilder, state, this).generate(); - } - } - - @Override - protected void generateErasedInlineClassIfNeeded() { - if (!(myClass instanceof KtClass)) return; - if (!InlineClassesUtilsKt.isInlineClass(descriptor)) return; - - ClassContext erasedInlineClassContext = context.intoWrapperForErasedInlineClass(descriptor, state); - new ErasedInlineClassBodyCodegen((KtClass) myClass, erasedInlineClassContext, v, state, this).generate(); - } - - @Override - protected void generateUnboxMethodForInlineClass() { - if (!(myClass instanceof KtClass)) return; - if (!InlineClassesUtilsKt.isInlineClass(descriptor)) return; - - Type ownerType = typeMapper.mapClass(descriptor); - ValueParameterDescriptor inlinedValue = InlineClassesUtilsKt.underlyingRepresentation(this.descriptor); - if (inlinedValue == null) return; - - Type valueType = typeMapper.mapType(inlinedValue.getType()); - SimpleFunctionDescriptor functionDescriptor = InlineClassDescriptorResolver.createUnboxFunctionDescriptor(this.descriptor); - assert functionDescriptor != null : "FunctionDescriptor for unbox method should be not null during codegen"; - - functionCodegen.generateMethod( - JvmDeclarationOriginKt.UnboxMethodOfInlineClass(functionDescriptor), functionDescriptor, - new FunctionGenerationStrategy.CodegenBased(state) { - @Override - public void doGenerateBody( - @NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature - ) { - InstructionAdapter iv = codegen.v; - iv.load(0, OBJECT_TYPE); - iv.getfield(ownerType.getInternalName(), inlinedValue.getName().asString(), valueType.getDescriptor()); - iv.areturn(valueType); - } - } - ); - } - - @Override - protected void generateKotlinMetadataAnnotation() { - ProtoBuf.Class classProto = serializer.classProto(descriptor).build(); - - WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.CLASS, 0, av -> { - writeAnnotationData(av, serializer, classProto); - return Unit.INSTANCE; - }); - } - - private void writeEnclosingMethod() { - // Do not emit enclosing method in "light-classes mode" since currently we generate local light classes as if they're top level - if (!state.getClassBuilderMode().generateBodies) { - return; - } - - //JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class. - if (isAnonymousObject(descriptor) || !(descriptor.getContainingDeclaration() instanceof ClassOrPackageFragmentDescriptor)) { - writeOuterClassAndEnclosingMethod(); - } - } - - private static final Map KOTLIN_MARKER_INTERFACES = new HashMap<>(); - - static { - for (PlatformMutabilityMapping platformMutabilityMapping : JavaToKotlinClassMap.INSTANCE.getMutabilityMappings()) { - KOTLIN_MARKER_INTERFACES.put( - platformMutabilityMapping.getKotlinReadOnly().asSingleFqName(), - "kotlin/jvm/internal/markers/KMappedMarker"); - - ClassId mutableClassId = platformMutabilityMapping.getKotlinMutable(); - KOTLIN_MARKER_INTERFACES.put( - mutableClassId.asSingleFqName(), - "kotlin/jvm/internal/markers/K" + mutableClassId.getRelativeClassName().asString() - .replace("MutableEntry", "Entry") // kotlin.jvm.internal.markers.KMutableMap.Entry for some reason - .replace(".", "$") - ); - } - } - - @NotNull - private JvmClassSignature signature() { - return signature(descriptor, classAsmType, superClassInfo, typeMapper); - } - - @NotNull - public static JvmClassSignature signature( - @NotNull ClassDescriptor descriptor, - @NotNull Type classAsmType, - @NotNull SuperClassInfo superClassInfo, - @NotNull KotlinTypeMapper typeMapper - ) { - JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); - - typeMapper.writeFormalTypeParameters(descriptor.getDeclaredTypeParameters(), sw); - - sw.writeSuperclass(); - if (superClassInfo.getKotlinType() == null) { - sw.writeClassBegin(superClassInfo.getType()); - sw.writeClassEnd(); - } - else { - typeMapper.mapSupertype(superClassInfo.getKotlinType(), sw); - } - sw.writeSuperclassEnd(); - - LinkedHashSet superInterfaces = new LinkedHashSet<>(); - Set kotlinMarkerInterfaces = new LinkedHashSet<>(); - - for (KotlinType supertype : descriptor.getTypeConstructor().getSupertypes()) { - if (isJvmInterface(supertype.getConstructor().getDeclarationDescriptor())) { - FqName kotlinInterfaceName = DescriptorUtils.getFqName(supertype.getConstructor().getDeclarationDescriptor()).toSafe(); - - sw.writeInterface(); - Type jvmInterfaceType = typeMapper.mapSupertype(supertype, sw); - sw.writeInterfaceEnd(); - String jvmInterfaceInternalName = jvmInterfaceType.getInternalName(); - - superInterfaces.add(jvmInterfaceInternalName); - - String kotlinMarkerInterfaceInternalName = KOTLIN_MARKER_INTERFACES.get(kotlinInterfaceName); - if (kotlinMarkerInterfaceInternalName != null) { - if (typeMapper.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) { - sw.writeInterface(); - Type kotlinCollectionType = typeMapper.mapType(supertype, sw, TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS); - sw.writeInterfaceEnd(); - superInterfaces.add(kotlinCollectionType.getInternalName()); - } - - kotlinMarkerInterfaces.add(kotlinMarkerInterfaceInternalName); - } - } - } - - for (String kotlinMarkerInterface : kotlinMarkerInterfaces) { - sw.writeInterface(); - sw.writeAsmType(getObjectType(kotlinMarkerInterface)); - sw.writeInterfaceEnd(); - } - - superInterfaces.addAll(kotlinMarkerInterfaces); - - return new JvmClassSignature(classAsmType.getInternalName(), superClassInfo.getType().getInternalName(), - new ArrayList<>(superInterfaces), sw.makeJavaGenericSignature()); - } - - @Override - protected void generateSyntheticPartsBeforeBody() { - generatePropertyMetadataArrayFieldIfNeeded(classAsmType); - } - - @Override - protected void generateSyntheticPartsAfterBody() { - generateFieldForSingleton(); - - initializeObjects(); - - generateCompanionObjectBackingFieldCopies(); - - generateDelegatesToDefaultImpl(); - - generateDelegates(delegationFieldsInfo); - - generateSyntheticAccessors(); - - generateEnumMethods(); - - generateFunctionsForDataClasses(); - - generateFunctionsFromAnyForInlineClasses(); - - if (state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) { - new CollectionStubMethodGenerator(typeMapper, descriptor).generate(functionCodegen, v); - - generateToArray(); - } - - - if (context.closure != null) - genClosureFields(context.closure, v, typeMapper, state.getLanguageVersionSettings()); - - for (ExpressionCodegenExtension extension : ExpressionCodegenExtension.Companion.getInstances(state.getProject())) { - if (state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES - || extension.getShouldGenerateClassSyntheticPartsInLightClassesMode() - ) { - extension.generateClassSyntheticParts(this); - } - } - } - - @Override - protected void generateConstructors() { - try { - lookupConstructorExpressionsInClosureIfPresent(); - constructorCodegen.generatePrimaryConstructor(delegationFieldsInfo, superClassAsmType); - if (!InlineClassesUtilsKt.isInlineClass(descriptor) && !(descriptor instanceof SyntheticClassOrObjectDescriptor)) { - // Synthetic classes does not have declarations for secondary constructors - for (ClassConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) { - constructorCodegen.generateSecondaryConstructor(secondaryConstructor, superClassAsmType); - } - } - } - catch (CompilationException | ProcessCanceledException e) { - throw e; - } - catch (RuntimeException e) { - throw new RuntimeException("Error generating constructors of class " + myClass.getName() + " with kind " + kind, e); - } - } - - private void generateToArray() { - if (descriptor.getKind() == ClassKind.INTERFACE) return; - - KotlinBuiltIns builtIns = DescriptorUtilsKt.getBuiltIns(descriptor); - if (!isSubclass(descriptor, builtIns.getCollection())) return; - - if (CollectionsKt.any(DescriptorUtilsKt.getAllSuperclassesWithoutAny(descriptor), - classDescriptor -> !(classDescriptor instanceof JavaClassDescriptor) && - isSubclass(classDescriptor, builtIns.getCollection()))) { - return; - } - - Collection functions = descriptor.getDefaultType().getMemberScope().getContributedFunctions( - Name.identifier("toArray"), NoLookupLocation.FROM_BACKEND - ); - boolean hasGenericToArray = false; - boolean hasNonGenericToArray = false; - for (FunctionDescriptor function : functions) { - hasGenericToArray |= isGenericToArray(function); - hasNonGenericToArray |= isNonGenericToArray(function); - } - - if (!hasNonGenericToArray) { - MethodVisitor mv = v.newMethod(NO_ORIGIN, ACC_PUBLIC, "toArray", "()[Ljava/lang/Object;", null, null); - - InstructionAdapter iv = new InstructionAdapter(mv); - mv.visitCode(); - - iv.load(0, classAsmType); - iv.invokestatic("kotlin/jvm/internal/CollectionToArray", "toArray", "(Ljava/util/Collection;)[Ljava/lang/Object;", false); - iv.areturn(Type.getType("[Ljava/lang/Object;")); - - FunctionCodegen.endVisit(mv, "toArray", myClass); - } - - if (!hasGenericToArray) { - MethodVisitor mv = v.newMethod( - NO_ORIGIN, ACC_PUBLIC, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;", "([TT;)[TT;", null); - - InstructionAdapter iv = new InstructionAdapter(mv); - mv.visitCode(); - - iv.load(0, classAsmType); - iv.load(1, Type.getType("[Ljava/lang/Object;")); - - iv.invokestatic("kotlin/jvm/internal/CollectionToArray", "toArray", - "(Ljava/util/Collection;[Ljava/lang/Object;)[Ljava/lang/Object;", false); - iv.areturn(Type.getType("[Ljava/lang/Object;")); - - FunctionCodegen.endVisit(mv, "toArray", myClass); - } - } - - public static JvmKotlinType genPropertyOnStack( - InstructionAdapter iv, - MethodContext context, - @NotNull PropertyDescriptor propertyDescriptor, - Type classAsmType, - int index, - GenerationState state - ) { - iv.load(index, classAsmType); - if (couldUseDirectAccessToProperty(propertyDescriptor, /* forGetter = */ true, - /* isDelegated = */ false, context, state.getShouldInlineConstVals())) { - KotlinType kotlinType = propertyDescriptor.getType(); - Type type = state.getTypeMapper().mapType(kotlinType); - String fieldName = ((FieldOwnerContext) context.getParentContext()).getFieldName(propertyDescriptor, false); - iv.getfield(classAsmType.getInternalName(), fieldName, type.getDescriptor()); - return new JvmKotlinType(type, kotlinType); - } - else { - PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); - - //noinspection ConstantConditions - Method method = state.getTypeMapper().mapAsmMethod(getter); - iv.invokevirtual(classAsmType.getInternalName(), method.getName(), method.getDescriptor(), false); - return new JvmKotlinType(method.getReturnType(), getter.getReturnType()); - } - } - - private void generateFunctionsForDataClasses() { - if (!descriptor.isData()) return; - if (!(myClass instanceof KtClassOrObject)) return; - new DataClassMethodGeneratorImpl((KtClassOrObject)myClass, bindingContext).generate(); - } - - private void generateFunctionsFromAnyForInlineClasses() { - if (!InlineClassesUtilsKt.isInlineClass(descriptor)) return; - if (!(myClass instanceof KtClassOrObject)) return; - new FunctionsFromAnyGeneratorImpl( - (KtClassOrObject) myClass, bindingContext, descriptor, classAsmType, context, v, state - ).generate(); - } - - private class DataClassMethodGeneratorImpl extends DataClassMethodGenerator { - private final FunctionsFromAnyGeneratorImpl functionsFromAnyGenerator; - - DataClassMethodGeneratorImpl( - KtClassOrObject klass, - BindingContext bindingContext - ) { - super(klass, bindingContext); - this.functionsFromAnyGenerator = new FunctionsFromAnyGeneratorImpl( - klass, bindingContext, descriptor, classAsmType, ImplementationBodyCodegen.this.context, v, state - ); - } - - @Override - public void generateEqualsMethod(@NotNull FunctionDescriptor function, @NotNull List properties) { - functionsFromAnyGenerator.generateEqualsMethod(function, properties); - } - - @Override - public void generateHashCodeMethod(@NotNull FunctionDescriptor function, @NotNull List properties) { - functionsFromAnyGenerator.generateHashCodeMethod(function, properties); - } - - @Override - public void generateToStringMethod(@NotNull FunctionDescriptor function, @NotNull List properties) { - functionsFromAnyGenerator.generateToStringMethod(function, properties); - } - - @Override - public void generateComponentFunction(@NotNull FunctionDescriptor function, @NotNull ValueParameterDescriptor parameter) { - PsiElement originalElement = DescriptorToSourceUtils.descriptorToDeclaration(parameter); - functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(originalElement, function), function, new FunctionGenerationStrategy() { - @Override - public void generateBody( - @NotNull MethodVisitor mv, - @NotNull FrameMap frameMap, - @NotNull JvmMethodSignature signature, - @NotNull MethodContext context, - @NotNull MemberCodegen parentCodegen - ) { - Type componentType = signature.getReturnType(); - InstructionAdapter iv = new InstructionAdapter(mv); - if (!componentType.equals(Type.VOID_TYPE)) { - PropertyDescriptor property = - bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, descriptorToDeclaration(parameter)); - assert property != null : "Property descriptor is not found for primary constructor parameter: " + parameter; - - JvmKotlinType propertyType = genPropertyOnStack( - iv, context, property, ImplementationBodyCodegen.this.classAsmType, 0, state - ); - StackValue.coerce(propertyType.getType(), componentType, iv); - } - iv.areturn(componentType); - } - - @Override - public boolean skipNotNullAssertionsForParameters() { - return false; - } - }); - } - - @Override - public void generateCopyFunction( - @NotNull FunctionDescriptor function, - @NotNull List constructorParameters - ) { - Type thisDescriptorType = typeMapper.mapType(descriptor); - - functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOriginFromPure(myClass, function), function, new FunctionGenerationStrategy() { - @Override - public void generateBody( - @NotNull MethodVisitor mv, - @NotNull FrameMap frameMap, - @NotNull JvmMethodSignature signature, - @NotNull MethodContext context, - @NotNull MemberCodegen parentCodegen - ) { - InstructionAdapter iv = new InstructionAdapter(mv); - - iv.anew(thisDescriptorType); - iv.dup(); - - ConstructorDescriptor constructor = getPrimaryConstructorOfDataClass(descriptor); - assert function.getValueParameters().size() == constructor.getValueParameters().size() : - "Number of parameters of copy function and constructor are different. " + - "Copy: " + function.getValueParameters().size() + ", " + - "constructor: " + constructor.getValueParameters().size(); - - MutableClosure closure = ImplementationBodyCodegen.this.context.closure; - if (closure != null) { - pushCapturedFieldsOnStack(iv, closure); - } - - int parameterIndex = 1; // localVariable 0 = this - for (ValueParameterDescriptor parameterDescriptor : function.getValueParameters()) { - Type type = typeMapper.mapType(parameterDescriptor.getType()); - iv.load(parameterIndex, type); - parameterIndex += type.getSize(); - } - - Method constructorAsmMethod = typeMapper.mapAsmMethod(constructor); - iv.invokespecial(thisDescriptorType.getInternalName(), "", constructorAsmMethod.getDescriptor(), false); - - iv.areturn(thisDescriptorType); - } - - @Override - public boolean skipNotNullAssertionsForParameters() { - return false; - } - - private void pushCapturedFieldsOnStack(InstructionAdapter iv, MutableClosure closure) { - ClassDescriptor captureThis = closure.getCapturedOuterClassDescriptor(); - if (captureThis != null) { - iv.load(0, classAsmType); - Type type = typeMapper.mapType(captureThis); - iv.getfield(classAsmType.getInternalName(), CAPTURED_THIS_FIELD, type.getDescriptor()); - } - - KotlinType captureReceiver = closure.getCapturedReceiverFromOuterContext(); - if (captureReceiver != null) { - iv.load(0, classAsmType); - Type type = typeMapper.mapType(captureReceiver); - String fieldName = closure.getCapturedReceiverFieldName(bindingContext, state.getLanguageVersionSettings()); - iv.getfield(classAsmType.getInternalName(), fieldName, type.getDescriptor()); - } - - for (Map.Entry entry : closure.getCaptureVariables().entrySet()) { - DeclarationDescriptor declarationDescriptor = entry.getKey(); - EnclosedValueDescriptor enclosedValueDescriptor = entry.getValue(); - StackValue capturedValue = enclosedValueDescriptor.getInstanceValue(); - Type sharedVarType = typeMapper.getSharedVarType(declarationDescriptor); - if (sharedVarType == null) { - sharedVarType = typeMapper.mapType((VariableDescriptor) declarationDescriptor); - } - capturedValue.put(sharedVarType, iv); - } - } - }); - - functionCodegen.generateDefaultIfNeeded( - context.intoFunction(function), function, OwnerKind.IMPLEMENTATION, - (valueParameter, codegen) -> { - assert ((ClassDescriptor) function.getContainingDeclaration()).isData() - : "Function container must have [data] modifier: " + function; - PropertyDescriptor property = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameter); - assert property != null : "Copy function doesn't correspond to any property: " + function; - return codegen.intermediateValueForProperty(property, false, null, StackValue.LOCAL_0); - }, - null - ); - } - } - - @NotNull - private static ConstructorDescriptor getPrimaryConstructorOfDataClass(@NotNull ClassDescriptor classDescriptor) { - ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); - assert constructor != null : "Data class must have primary constructor: " + classDescriptor; - return constructor; - } - - private void generateEnumMethods() { - if (isEnumClass(descriptor)) { - generateEnumValuesMethod(); - generateEnumValueOfMethod(); - } - } - - private void generateEnumValuesMethod() { - Type type = typeMapper.mapType(DescriptorUtilsKt.getBuiltIns(descriptor).getArrayType(INVARIANT, descriptor.getDefaultType())); - - FunctionDescriptor valuesFunction = - CollectionsKt.single(descriptor.getStaticScope().getContributedFunctions(ENUM_VALUES, NoLookupLocation.FROM_BACKEND)); - MethodVisitor mv = v.newMethod( - JvmDeclarationOriginKt.OtherOriginFromPure(myClass, valuesFunction), ACC_PUBLIC | ACC_STATIC, ENUM_VALUES.asString(), - "()" + type.getDescriptor(), null, null - ); - if (!state.getClassBuilderMode().generateBodies) return; - - mv.visitCode(); - mv.visitFieldInsn(GETSTATIC, classAsmType.getInternalName(), ENUM_VALUES_FIELD_NAME, type.getDescriptor()); - mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), "clone", "()Ljava/lang/Object;", false); - mv.visitTypeInsn(CHECKCAST, type.getInternalName()); - mv.visitInsn(ARETURN); - FunctionCodegen.endVisit(mv, "values()", myClass); - } - - private void generateEnumValueOfMethod() { - FunctionDescriptor valueOfFunction = - CollectionsKt.single(descriptor.getStaticScope().getContributedFunctions(ENUM_VALUE_OF, NoLookupLocation.FROM_BACKEND), - DescriptorUtilsKt::isEnumValueOfMethod); - MethodVisitor mv = - v.newMethod(JvmDeclarationOriginKt.OtherOriginFromPure(myClass, valueOfFunction), ACC_PUBLIC | ACC_STATIC, ENUM_VALUE_OF.asString(), - "(Ljava/lang/String;)" + classAsmType.getDescriptor(), null, null); - if (!state.getClassBuilderMode().generateBodies) return; - - mv.visitCode(); - mv.visitLdcInsn(classAsmType); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;", false); - mv.visitTypeInsn(CHECKCAST, classAsmType.getInternalName()); - mv.visitInsn(ARETURN); - FunctionCodegen.endVisit(mv, "valueOf()", myClass); - } - - private void generateFieldForSingleton() { - if (isCompanionObjectInInterfaceNotIntrinsic(descriptor)) { - StackValue.Field field = StackValue.createSingletonViaInstance(descriptor, typeMapper, HIDDEN_INSTANCE_FIELD); - //hidden instance in interface companion - v.newField(JvmDeclarationOriginKt.OtherOrigin(descriptor), - ACC_SYNTHETIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null); - } - - if (isEnumEntry(descriptor) || isCompanionObject(descriptor)) return; - - if (isNonCompanionObject(descriptor)) { - StackValue.Field field = StackValue.createSingletonViaInstance(descriptor, typeMapper, INSTANCE_FIELD); - FieldVisitor fv = v.newField( - JvmDeclarationOriginKt.OtherOriginFromPure(myClass), - ACC_PUBLIC | ACC_STATIC | ACC_FINAL, - field.name, field.type.getDescriptor(), null, null - ); - AnnotationCodegen.forField(fv, this, state).visitAnnotation(Type.getDescriptor(NotNull.class), false).visitEnd(); - return; - } - - ClassDescriptor companionObjectDescriptor = descriptor.getCompanionObjectDescriptor(); - if (companionObjectDescriptor == null) { - return; - } - - @Nullable KtObjectDeclaration companionObject = CollectionsKt.firstOrNull(myClass.getCompanionObjects()); - - int properFieldVisibilityFlag = getVisibilityAccessFlag(companionObjectDescriptor); - boolean deprecatedFieldForInvisibleCompanionObject = - state.getLanguageVersionSettings().supportsFeature(LanguageFeature.DeprecatedFieldForInvisibleCompanionObject); - boolean properVisibilityForCompanionObjectInstanceField = - state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ProperVisibilityForCompanionObjectInstanceField); - boolean hasPrivateOrProtectedProperVisibility = (properFieldVisibilityFlag & (ACC_PRIVATE | ACC_PROTECTED)) != 0; - boolean hasPackagePrivateProperVisibility = (properFieldVisibilityFlag & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)) == 0; - boolean fieldShouldBeDeprecated = - deprecatedFieldForInvisibleCompanionObject && - !properVisibilityForCompanionObjectInstanceField && - (hasPrivateOrProtectedProperVisibility || hasPackagePrivateProperVisibility || - isNonIntrinsicPrivateCompanionObjectInInterface(companionObjectDescriptor)); - boolean fieldIsForcedToBePublic = - JvmCodegenUtil.isJvmInterface(descriptor) || - !properVisibilityForCompanionObjectInstanceField; - int fieldAccessFlags = ACC_STATIC | ACC_FINAL; - if (fieldIsForcedToBePublic) { - fieldAccessFlags |= ACC_PUBLIC; - } - else { - fieldAccessFlags |= properFieldVisibilityFlag; - } - if (fieldShouldBeDeprecated) { - fieldAccessFlags |= ACC_DEPRECATED; - } - if (properVisibilityForCompanionObjectInstanceField && - JvmCodegenUtil.isCompanionObjectInInterfaceNotIntrinsic(companionObjectDescriptor) && - DescriptorVisibilities.isPrivate(companionObjectDescriptor.getVisibility())) { - fieldAccessFlags |= ACC_SYNTHETIC; - } - StackValue.Field field = StackValue.singleton(companionObjectDescriptor, typeMapper); - FieldVisitor fv = v.newField( - JvmDeclarationOriginKt.OtherOrigin(companionObject == null ? myClass.getPsiOrParent() : companionObject), - fieldAccessFlags, field.name, field.type.getDescriptor(), null, null - ); - AnnotationCodegen.forField(fv, this, state).visitAnnotation(Type.getDescriptor(NotNull.class), false).visitEnd(); - if (fieldShouldBeDeprecated) { - AnnotationCodegen.forField(fv, this, state).visitAnnotation(Type.getDescriptor(Deprecated.class), true).visitEnd(); - } - } - - private void initializeObjects() { - if (!DescriptorUtils.isObject(descriptor)) return; - if (!state.getClassBuilderMode().generateBodies) return; - - boolean isNonCompanionObject = isNonCompanionObject(descriptor); - boolean isInterfaceCompanion = isCompanionObjectInInterfaceNotIntrinsic(descriptor); - boolean isInterfaceCompanionWithBackingFieldsInOuter = isInterfaceCompanionWithBackingFieldsInOuter(descriptor); - boolean isMappedIntrinsicCompanionObject = isMappedIntrinsicCompanionObject(descriptor); - boolean isClassCompanionWithBackingFieldsInOuter = isClassCompanionObjectWithBackingFieldsInOuter(descriptor); - if (isNonCompanionObject || - (isInterfaceCompanion && !isInterfaceCompanionWithBackingFieldsInOuter) || - isMappedIntrinsicCompanionObject - ) { - ExpressionCodegen clInitCodegen = createOrGetClInitCodegen(); - InstructionAdapter v = clInitCodegen.v; - markLineNumberForElement(element.getPsiOrParent(), v); - v.anew(classAsmType); - v.dup(); - v.invokespecial(classAsmType.getInternalName(), "", "()V", false); - - //local0 emulates this in object constructor - int local0Index = clInitCodegen.getFrameMap().enterTemp(classAsmType); - assert local0Index == 0 : "Local variable with index 0 in clInit should be used only for singleton instance keeping"; - StackValue.Local local0 = StackValue.local(0, classAsmType); - local0.store(StackValue.onStack(classAsmType), clInitCodegen.v); - StackValue.Field singleton = - StackValue.createSingletonViaInstance( - descriptor, typeMapper, isInterfaceCompanion ? HIDDEN_INSTANCE_FIELD : INSTANCE_FIELD - ); - singleton.store(local0, clInitCodegen.v); - - generateInitializers(clInitCodegen); - - if (isInterfaceCompanion) { - //initialize singleton instance in outer by hidden instance - StackValue.singleton(descriptor, typeMapper).store( - singleton, getParentCodegen().createOrGetClInitCodegen().v, true - ); - } - } - else if (isClassCompanionWithBackingFieldsInOuter || isInterfaceCompanionWithBackingFieldsInOuter) { - ImplementationBodyCodegen parentCodegen = (ImplementationBodyCodegen) getParentCodegen(); - ExpressionCodegen parentClInitCodegen = parentCodegen.createOrGetClInitCodegen(); - InstructionAdapter parentVisitor = parentClInitCodegen.v; - - FunctionDescriptor constructor = (FunctionDescriptor) parentCodegen.context.accessibleDescriptor( - CollectionsKt.single(descriptor.getConstructors()), /* superCallExpression = */ null - ); - parentCodegen.generateMethodCallTo(constructor, null, parentVisitor); - StackValue instance = StackValue.onStack(parentCodegen.typeMapper.mapClass(descriptor)); - StackValue.singleton(descriptor, parentCodegen.typeMapper).store(instance, parentVisitor, true); - - generateInitializers(parentClInitCodegen); - } - else { - assert false : "Unknown object type: " + descriptor; - } - } - - private static boolean isInterfaceCompanionWithBackingFieldsInOuter(@NotNull DeclarationDescriptor declarationDescriptor) { - DeclarationDescriptor interfaceClass = declarationDescriptor.getContainingDeclaration(); - if (!isCompanionObject(declarationDescriptor) || !isJvmInterface(interfaceClass)) return false; - - Collection descriptors = ((ClassDescriptor) declarationDescriptor).getUnsubstitutedMemberScope() - .getContributedDescriptors(DescriptorKindFilter.ALL, MemberScope.Companion.getALL_NAME_FILTER()); - return CollectionsKt.any(descriptors, d -> d instanceof PropertyDescriptor && hasJvmFieldAnnotation((PropertyDescriptor) d)); - } - - private void generateCompanionObjectBackingFieldCopies() { - if (companionObjectPropertiesToCopy == null || companionObjectPropertiesToCopy.isEmpty()) return; - - boolean isPrivateCompanion = - DescriptorVisibilities.isPrivate( - ((ClassDescriptor) companionObjectPropertiesToCopy.get(0).descriptor.getContainingDeclaration()).getVisibility()); - - int modifiers = ACC_STATIC | ACC_FINAL | ACC_PUBLIC | (isPrivateCompanion ? ACC_DEPRECATED : 0); - List additionalVisibleAnnotations = - isPrivateCompanion ? Collections.singletonList(CodegenUtilKt.JAVA_LANG_DEPRECATED) : Collections.emptyList(); - for (PropertyAndDefaultValue info : companionObjectPropertiesToCopy) { - PropertyDescriptor property = info.descriptor; - - Type type = typeMapper.mapType(property); - - FieldVisitor fv = v.newField(JvmDeclarationOriginKt.Synthetic(DescriptorToSourceUtils.descriptorToDeclaration(property), property), - modifiers, context.getFieldName(property, false), - type.getDescriptor(), typeMapper.mapFieldSignature(property.getType(), property), - info.defaultValue); - - AnnotationCodegen.forField(fv, this, state).genAnnotations(property, type, null, null, additionalVisibleAnnotations); - - //This field are always static and final so if it has constant initializer don't do anything in clinit, - //field would be initialized via default value in v.newField(...) - see JVM SPEC Ch.4 - // TODO: test this code - if (state.getClassBuilderMode().generateBodies && info.defaultValue == null) { - ExpressionCodegen codegen = createOrGetClInitCodegen(); - int companionObjectIndex = putCompanionObjectInLocalVar(codegen); - StackValue.local(companionObjectIndex, OBJECT_TYPE).put(codegen.v); - copyFieldFromCompanionObject(property); - } - } - } - - private int putCompanionObjectInLocalVar(ExpressionCodegen codegen) { - FrameMap frameMap = codegen.myFrameMap; - ClassDescriptor companionObjectDescriptor = descriptor.getCompanionObjectDescriptor(); - int companionObjectIndex = frameMap.getIndex(companionObjectDescriptor); - if (companionObjectIndex == -1) { - companionObjectIndex = frameMap.enter(companionObjectDescriptor, OBJECT_TYPE); - StackValue companionObject = StackValue.singleton(companionObjectDescriptor, typeMapper); - StackValue.local(companionObjectIndex, companionObject.type).store(companionObject, codegen.v); - } - return companionObjectIndex; - } - - private void copyFieldFromCompanionObject(PropertyDescriptor propertyDescriptor) { - ExpressionCodegen codegen = createOrGetClInitCodegen(); - StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, false, null, StackValue.none()); - StackValue.Field field = StackValue.field( - property.type, property.kotlinType, classAsmType, propertyDescriptor.getName().asString(), - true, StackValue.none(), propertyDescriptor - ); - field.store(property, codegen.v); - } - - public void generateInitializers(@NotNull ExpressionCodegen codegen) { - generateInitializers(() -> codegen); - } - - private void lookupConstructorExpressionsInClosureIfPresent() { - if (!state.getClassBuilderMode().generateBodies || descriptor.getConstructors().isEmpty()) return; - - KtVisitorVoid visitor = new KtVisitorVoid() { - @Override - public void visitKtElement(@NotNull KtElement e) { - e.acceptChildren(this); - } - - @Override - public void visitSimpleNameExpression(@NotNull KtSimpleNameExpression expr) { - DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr); - - if (isLocalFunction(descriptor)) { - lookupInContext(descriptor); - } - else if (descriptor instanceof CallableMemberDescriptor) { - ResolvedCall call = CallUtilKt.getResolvedCall(expr, bindingContext); - if (call != null) { - lookupReceivers(call); - } - if (call instanceof VariableAsFunctionResolvedCall) { - lookupReceivers(((VariableAsFunctionResolvedCall) call).getVariableCall()); - } - } - else if (descriptor instanceof VariableDescriptor) { - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); - if (containingDeclaration instanceof ConstructorDescriptor) { - ClassDescriptor classDescriptor = ((ConstructorDescriptor) containingDeclaration).getConstructedClass(); - if (classDescriptor == ImplementationBodyCodegen.this.descriptor) return; - } - if (lookupInContext(descriptor)) { - if (isDelegatedLocalVariable(descriptor)) { - VariableDescriptor metadata = getDelegatedLocalVariableMetadata((VariableDescriptor) descriptor, bindingContext); - lookupInContext(metadata); - } - } - } - } - - private void lookupReceivers(@NotNull ResolvedCall call) { - lookupReceiver(call.getDispatchReceiver()); - lookupReceiver(call.getExtensionReceiver()); - } - - private void lookupReceiver(@Nullable ReceiverValue value) { - if (value instanceof ImplicitReceiver) { - if (value instanceof ExtensionReceiver) { - ReceiverParameterDescriptor parameter = - ((ExtensionReceiver) value).getDeclarationDescriptor().getExtensionReceiverParameter(); - assert parameter != null : "Extension receiver should exist: " + ((ExtensionReceiver) value).getDeclarationDescriptor(); - lookupInContext(parameter); - } - else { - lookupInContext(((ImplicitReceiver) value).getDeclarationDescriptor()); - } - } - } - - private boolean lookupInContext(@NotNull DeclarationDescriptor toLookup) { - return context.lookupInContext(toLookup, StackValue.LOCAL_0, state, true) != null; - } - - @Override - public void visitThisExpression(@NotNull KtThisExpression expression) { - DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()); - assert descriptor instanceof CallableDescriptor || - descriptor instanceof ClassDescriptor : "'This' reference target should be class or callable descriptor but was " + descriptor; - if (descriptor instanceof ClassDescriptor) { - lookupInContext(descriptor); - } - - if (descriptor instanceof CallableDescriptor) { - ReceiverParameterDescriptor parameter = ((CallableDescriptor) descriptor).getExtensionReceiverParameter(); - if (parameter != null) { - lookupInContext(parameter); - } - } - } - - @Override - public void visitSuperExpression(@NotNull KtSuperExpression expression) { - lookupInContext(ExpressionCodegen.getSuperCallLabelTarget(context, expression)); - } - - @Override - public void visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression) { - ResolvedCall resolvedGetCall = bindingContext.get(INDEXED_LVALUE_GET, expression); - if (resolvedGetCall != null) { - ReceiverValue receiver = resolvedGetCall.getDispatchReceiver(); - lookupReceiver(receiver); - } - - ResolvedCall resolvedSetCall = bindingContext.get(INDEXED_LVALUE_SET, expression); - if (resolvedSetCall != null) { - ReceiverValue receiver = resolvedSetCall.getDispatchReceiver(); - lookupReceiver(receiver); - } - super.visitArrayAccessExpression(expression); - } - }; - - for (KtDeclaration declaration : myClass.getDeclarations()) { - if (declaration instanceof KtProperty) { - KtProperty property = (KtProperty) declaration; - KtExpression initializer = property.getDelegateExpressionOrInitializer(); - if (initializer != null) { - initializer.accept(visitor); - } - } - else if (declaration instanceof KtAnonymousInitializer) { - KtAnonymousInitializer initializer = (KtAnonymousInitializer) declaration; - initializer.accept(visitor); - } - else if (declaration instanceof KtSecondaryConstructor) { - KtSecondaryConstructor constructor = (KtSecondaryConstructor) declaration; - constructor.accept(visitor); - } - } - - for (KtSuperTypeListEntry specifier : myClass.getSuperTypeListEntries()) { - if (specifier instanceof KtDelegatedSuperTypeEntry) { - KtExpression delegateExpression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression(); - assert delegateExpression != null; - delegateExpression.accept(visitor); - } - else if (specifier instanceof KtSuperTypeCallEntry) { - specifier.accept(visitor); - } - } - } - - private void generateEnumEntries() { - if (descriptor.getKind() != ClassKind.ENUM_CLASS) return; - - List enumEntries = CollectionsKt.filterIsInstance(element.getDeclarations(), KtEnumEntry.class); - - for (KtEnumEntry enumEntry : enumEntries) { - ClassDescriptor descriptor = getNotNull(bindingContext, BindingContext.CLASS, enumEntry); - int isDeprecated = KotlinBuiltIns.isDeprecated(descriptor) ? ACC_DEPRECATED : 0; - FieldVisitor fv = v.newField(JvmDeclarationOriginKt.OtherOrigin(enumEntry, descriptor), ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL | isDeprecated, - descriptor.getName().asString(), classAsmType.getDescriptor(), null, null); - AnnotationCodegen.forField(fv, this, state).genAnnotations(descriptor, null, null); - } - - initializeEnumConstants(enumEntries); - } - - private void initializeEnumConstants(@NotNull List enumEntries) { - if (!state.getClassBuilderMode().generateBodies) return; - - ExpressionCodegen codegen = createOrGetClInitCodegen(); - InstructionAdapter iv = codegen.v; - - Type arrayAsmType = typeMapper.mapType(DescriptorUtilsKt.getBuiltIns(descriptor).getArrayType(INVARIANT, descriptor.getDefaultType())); - v.newField(JvmDeclarationOriginKt.OtherOriginFromPure(myClass), ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, ENUM_VALUES_FIELD_NAME, - arrayAsmType.getDescriptor(), null, null); - - iv.iconst(enumEntries.size()); - iv.newarray(classAsmType); - - if (!enumEntries.isEmpty()) { - iv.dup(); - for (int ordinal = 0, size = enumEntries.size(); ordinal < size; ordinal++) { - initializeEnumConstant(enumEntries, ordinal); - } - } - - iv.putstatic(classAsmType.getInternalName(), ENUM_VALUES_FIELD_NAME, arrayAsmType.getDescriptor()); - } - - private void initializeEnumConstant(@NotNull List enumEntries, int ordinal) { - ExpressionCodegen codegen = createOrGetClInitCodegen(); - InstructionAdapter iv = codegen.v; - KtEnumEntry enumEntry = enumEntries.get(ordinal); - - iv.dup(); - iv.iconst(ordinal); - - ClassDescriptor classDescriptor = getNotNull(bindingContext, BindingContext.CLASS, enumEntry); - Type implClass = typeMapper.mapClass(classDescriptor); - - iv.anew(implClass); - iv.dup(); - - iv.aconst(enumEntry.getName()); - iv.iconst(ordinal); - - List delegationSpecifiers = enumEntry.getSuperTypeListEntries(); - ResolvedCall defaultArgumentsConstructorCall = CallUtilKt.getResolvedCall(enumEntry, bindingContext); - boolean enumEntryHasSubclass = CodegenBinding.enumEntryNeedSubclass(bindingContext, classDescriptor); - if (delegationSpecifiers.size() == 1 && !enumEntryNeedSubclass(bindingContext, enumEntry)) { - ResolvedCall resolvedCall = CallUtilKt.getResolvedCallWithAssert(delegationSpecifiers.get(0), bindingContext); - - CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) resolvedCall.getResultingDescriptor(), false); - - codegen.invokeMethodWithArguments(method, resolvedCall, StackValue.none()); - } - else if (defaultArgumentsConstructorCall != null && !enumEntryHasSubclass) { - codegen.invokeFunction(defaultArgumentsConstructorCall, StackValue.none()).put(Type.VOID_TYPE, iv); - } - else { - iv.invokespecial(implClass.getInternalName(), "", "(Ljava/lang/String;I)V", false); - } - - iv.dup(); - iv.putstatic(classAsmType.getInternalName(), enumEntry.getName(), classAsmType.getDescriptor()); - iv.astore(OBJECT_TYPE); - } - - private void generateDelegates(DelegationFieldsInfo delegationFieldsInfo) { - for (KtSuperTypeListEntry specifier : myClass.getSuperTypeListEntries()) { - if (specifier instanceof KtDelegatedSuperTypeEntry) { - DelegationFieldsInfo.Field field = delegationFieldsInfo.getInfo((KtDelegatedSuperTypeEntry) specifier); - if (field == null) continue; - - generateDelegateField(field); - KtExpression delegateExpression = ((KtDelegatedSuperTypeEntry) specifier).getDelegateExpression(); - KotlinType delegateExpressionType = delegateExpression != null ? bindingContext.getType(delegateExpression) : null; - ClassDescriptor superClass = JvmCodegenUtil.getSuperClass(specifier, state, bindingContext); - if (superClass == null) continue; - - generateDelegates(superClass, delegateExpressionType, field); - } - } - } - - private void generateDelegateField(DelegationFieldsInfo.Field fieldInfo) { - if (!fieldInfo.generateField) return; - - v.newField(JvmDeclarationOrigin.NO_ORIGIN, ACC_PRIVATE | ACC_FINAL | ACC_SYNTHETIC, - fieldInfo.name, fieldInfo.type.getDescriptor(), fieldInfo.genericSignature, null); - } - - private void generateDelegates( - @NotNull ClassDescriptor toInterface, - @Nullable KotlinType delegateExpressionType, - @NotNull DelegationFieldsInfo.Field field - ) { - for (Map.Entry entry : DelegationResolver.Companion.getDelegates( - descriptor, toInterface, delegateExpressionType).entrySet() - ) { - CallableMemberDescriptor member = entry.getKey(); - CallableMemberDescriptor delegateTo = entry.getValue(); - if (member instanceof PropertyDescriptor) { - propertyCodegen.genDelegate((PropertyDescriptor) member, (PropertyDescriptor) delegateTo, field.getStackValue()); - } - else if (member instanceof FunctionDescriptor) { - functionCodegen.genDelegate((FunctionDescriptor) member, (FunctionDescriptor) delegateTo, field.getStackValue()); - } - } - } - - public void addCompanionObjectPropertyToCopy(@NotNull PropertyDescriptor descriptor, Object defaultValue) { - if (companionObjectPropertiesToCopy == null) { - companionObjectPropertiesToCopy = new ArrayList<>(); - } - companionObjectPropertiesToCopy.add(new PropertyAndDefaultValue(descriptor, defaultValue)); - } - - @Override - protected void done() { - for (Function2 task : additionalTasks) { - task.invoke(this, v); - } - - super.done(); - } - - private static class PropertyAndDefaultValue { - public final PropertyDescriptor descriptor; - public final Object defaultValue; - - public PropertyAndDefaultValue(@NotNull PropertyDescriptor descriptor, Object defaultValue) { - this.descriptor = descriptor; - this.defaultValue = defaultValue; - } - } - - public void addAdditionalTask(Function2 additionalTask) { - additionalTasks.add(additionalTask); - } -} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 449fb9a82d3..cc3c0046a4b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -454,7 +454,7 @@ public class PropertyCodegen { } if (propertyDescriptor.getContainingDeclaration() instanceof ClassDescriptor && JvmAnnotationUtilKt.isJvmRecord((ClassDescriptor) propertyDescriptor.getContainingDeclaration())) { - builder.newRecordComponent(name, type.getDescriptor(), signature); + ClassBuilderRecordKt.addRecordComponent(builder, name, type.getDescriptor(), signature); } } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java.201 b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java.201 deleted file mode 100644 index 25b7285eb81..00000000000 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java.201 +++ /dev/null @@ -1,680 +0,0 @@ -/* - * Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.codegen; - -import com.intellij.psi.PsiElement; -import kotlin.Pair; -import kotlin.collections.CollectionsKt; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.codegen.context.CodegenContextUtil; -import org.jetbrains.kotlin.codegen.context.FieldOwnerContext; -import org.jetbrains.kotlin.codegen.context.MultifileClassFacadeContext; -import org.jetbrains.kotlin.codegen.context.MultifileClassPartContext; -import org.jetbrains.kotlin.codegen.state.GenerationState; -import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; -import org.jetbrains.kotlin.config.LanguageFeature; -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.descriptors.annotations.Annotations; -import org.jetbrains.kotlin.load.java.DescriptorsJvmAbiUtil; -import org.jetbrains.kotlin.load.java.JvmAbi; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.resolve.BindingContext; -import org.jetbrains.kotlin.resolve.DescriptorFactory; -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; -import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt; -import org.jetbrains.kotlin.resolve.constants.ConstantValue; -import org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt; -import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor; -import org.jetbrains.kotlin.types.ErrorUtils; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.org.objectweb.asm.FieldVisitor; -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; -import org.jetbrains.org.objectweb.asm.commons.Method; - -import java.util.Collections; -import java.util.List; - -import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getDeprecatedAccessFlag; -import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getVisibilityForBackingField; -import static org.jetbrains.kotlin.codegen.FunctionCodegen.processInterfaceMethod; -import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation; -import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface; -import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*; -import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*; -import static org.jetbrains.kotlin.diagnostics.Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND; -import static org.jetbrains.kotlin.fileClasses.JvmFileClassUtilKt.isTopLevelInJvmMultifileClass; -import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject; -import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface; -import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.K_PROPERTY_TYPE; -import static org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.hasJvmFieldAnnotation; -import static org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.hasJvmSyntheticAnnotation; -import static org.jetbrains.org.objectweb.asm.Opcodes.*; - -public class PropertyCodegen { - private final GenerationState state; - private final ClassBuilder v; - private final FunctionCodegen functionCodegen; - private final KotlinTypeMapper typeMapper; - private final BindingContext bindingContext; - private final FieldOwnerContext context; - private final MemberCodegen memberCodegen; - private final OwnerKind kind; - - public PropertyCodegen( - @NotNull FieldOwnerContext context, - @NotNull ClassBuilder v, - @NotNull FunctionCodegen functionCodegen, - @NotNull MemberCodegen memberCodegen - ) { - this.state = functionCodegen.state; - this.v = v; - this.functionCodegen = functionCodegen; - this.typeMapper = state.getTypeMapper(); - this.bindingContext = state.getBindingContext(); - this.context = context; - this.memberCodegen = memberCodegen; - this.kind = context.getContextKind(); - } - - public void gen(@NotNull KtProperty property) { - VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, property); - if (!(variableDescriptor instanceof PropertyDescriptor)) { - throw ExceptionLogger.logDescriptorNotFound( - "Property " + property.getName() + " should have a property descriptor: " + variableDescriptor, property - ); - } - - PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor; - gen(property, propertyDescriptor, property.getGetter(), property.getSetter()); - } - - public void genDestructuringDeclaration(@NotNull KtDestructuringDeclarationEntry entry) { - VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, entry); - if (!(variableDescriptor instanceof PropertyDescriptor)) { - throw ExceptionLogger.logDescriptorNotFound( - "Destructuring declaration entry" + entry.getName() + " should have a property descriptor: " + variableDescriptor, entry - ); - } - - if (!UnderscoreUtilKt.isSingleUnderscore(entry)) { - genDestructuringDeclaration((PropertyDescriptor) variableDescriptor); - } - } - - public void generateInPackageFacade(@NotNull DeserializedPropertyDescriptor deserializedProperty) { - assert context instanceof MultifileClassFacadeContext : "should be called only for generating facade: " + context; - - genBackingFieldAndAnnotations(deserializedProperty); - - if (!isConstOrHasJvmFieldAnnotation(deserializedProperty)) { - generateGetter(deserializedProperty, null); - generateSetter(deserializedProperty, null); - } - } - - private void gen( - @NotNull KtProperty declaration, - @NotNull PropertyDescriptor descriptor, - @Nullable KtPropertyAccessor getter, - @Nullable KtPropertyAccessor setter - ) { - assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || - kind == OwnerKind.DEFAULT_IMPLS || kind == OwnerKind.ERASED_INLINE_CLASS - : "Generating property with a wrong kind (" + kind + "): " + descriptor; - - genBackingFieldAndAnnotations(descriptor); - - boolean isDefaultGetterAndSetter = isDefaultAccessor(getter) && isDefaultAccessor(setter); - - if (isAccessorNeeded(descriptor, getter, isDefaultGetterAndSetter)) { - generateGetter(descriptor, getter); - } - if (isAccessorNeeded(descriptor, setter, isDefaultGetterAndSetter)) { - generateSetter(descriptor, setter); - } - } - - private static boolean isDefaultAccessor(@Nullable KtPropertyAccessor accessor) { - return accessor == null || !accessor.hasBody(); - } - - private void genDestructuringDeclaration(@NotNull PropertyDescriptor descriptor) { - assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DEFAULT_IMPLS - : "Generating property with a wrong kind (" + kind + "): " + descriptor; - - genBackingFieldAndAnnotations(descriptor); - - generateGetter(descriptor, null); - generateSetter(descriptor, null); - } - - private void genBackingFieldAndAnnotations(@NotNull PropertyDescriptor descriptor) { - // Fields and '$annotations' methods for non-private const properties are generated in the multi-file facade - boolean isBackingFieldOwner = descriptor.isConst() && !DescriptorVisibilities.isPrivate(descriptor.getVisibility()) - ? !(context instanceof MultifileClassPartContext) - : CodegenContextUtil.isImplementationOwner(context, descriptor); - - generateBackingField(descriptor, isBackingFieldOwner); - generateSyntheticMethodIfNeeded(descriptor, isBackingFieldOwner); - } - - private boolean isAccessorNeeded( - @NotNull PropertyDescriptor descriptor, - @Nullable KtPropertyAccessor accessor, - boolean isDefaultGetterAndSetter - ) { - return isAccessorNeeded(descriptor, accessor, isDefaultGetterAndSetter, kind); - } - - public static boolean isReferenceablePropertyWithGetter(@NotNull PropertyDescriptor descriptor) { - PsiElement psiElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor); - KtDeclaration ktDeclaration = psiElement instanceof KtDeclaration ? (KtDeclaration) psiElement : null; - if (ktDeclaration instanceof KtProperty) { - KtProperty ktProperty = (KtProperty) ktDeclaration; - boolean isDefaultGetterAndSetter = - isDefaultAccessor(ktProperty.getGetter()) && isDefaultAccessor(ktProperty.getSetter()); - return isAccessorNeeded(descriptor, ktProperty.getGetter(), isDefaultGetterAndSetter, OwnerKind.IMPLEMENTATION); - } else if (ktDeclaration instanceof KtParameter) { - return isAccessorNeeded(descriptor, null, true, OwnerKind.IMPLEMENTATION); - } else { - return isAccessorNeeded(descriptor, null, false, OwnerKind.IMPLEMENTATION); - } - } - - /** - * Determines if it's necessary to generate an accessor to the property, i.e. if this property can be referenced via getter/setter - * for any reason - * - * @see JvmCodegenUtil#couldUseDirectAccessToProperty - */ - private static boolean isAccessorNeeded( - @NotNull PropertyDescriptor descriptor, - @Nullable KtPropertyAccessor accessor, - boolean isDefaultGetterAndSetter, - OwnerKind kind - ) { - if (isConstOrHasJvmFieldAnnotation(descriptor)) return false; - - boolean isDefaultAccessor = isDefaultAccessor(accessor); - - // Don't generate accessors for interface properties with default accessors in DefaultImpls - if (kind == OwnerKind.DEFAULT_IMPLS && isDefaultAccessor) return false; - - // Delegated or extension properties can only be referenced via accessors - if (descriptor.isDelegated() || descriptor.getExtensionReceiverParameter() != null) return true; - - // Companion object properties should have accessors for non-private properties because these properties can be referenced - // via getter/setter. But these accessors getter/setter are not required for private properties that have a default getter - // and setter, in this case, the property can always be accessed through the accessor 'access$cp' and avoid some - // useless indirection by using others accessors. - if (isCompanionObject(descriptor.getContainingDeclaration())) { - if (DescriptorVisibilities.isPrivate(descriptor.getVisibility()) && isDefaultGetterAndSetter) { - return false; - } - return true; - } - - // Non-const properties from multifile classes have accessors regardless of visibility - if (isTopLevelInJvmMultifileClass(descriptor)) return true; - - // Private class properties have accessors only in cases when those accessors are non-trivial - if (DescriptorVisibilities.isPrivate(descriptor.getVisibility())) { - return !isDefaultAccessor; - } - - // Non-private properties with private setter should not be generated for trivial properties - // as the class will use direct field access instead - //noinspection ConstantConditions - if (accessor != null && accessor.isSetter() && DescriptorVisibilities.isPrivate(descriptor.getSetter().getVisibility())) { - return !isDefaultAccessor; - } - - // Non-public API (private and internal) primary vals of inline classes don't have getter - if (InlineClassesUtilsKt.isUnderlyingPropertyOfInlineClass(descriptor) && !descriptor.getVisibility().isPublicAPI()) { - return false; - } - - return true; - } - - private static boolean areAccessorsNeededForPrimaryConstructorProperty( - @NotNull PropertyDescriptor descriptor, - @NotNull OwnerKind kind - ) { - if (hasJvmFieldAnnotation(descriptor)) return false; - if (kind == OwnerKind.ERASED_INLINE_CLASS) return false; - - DescriptorVisibility visibility = descriptor.getVisibility(); - if (InlineClassesUtilsKt.isInlineClass(descriptor.getContainingDeclaration())) { - return visibility.isPublicAPI(); - } - else { - return !DescriptorVisibilities.isPrivate(visibility); - } - } - - public void generatePrimaryConstructorProperty(@NotNull PropertyDescriptor descriptor) { - genBackingFieldAndAnnotations(descriptor); - - if (areAccessorsNeededForPrimaryConstructorProperty(descriptor, context.getContextKind())) { - generateGetter(descriptor, null); - generateSetter(descriptor, null); - } - } - - public void generateConstructorPropertyAsMethodForAnnotationClass( - @NotNull KtParameter parameter, - @NotNull PropertyDescriptor descriptor, - @Nullable FunctionDescriptor expectedAnnotationConstructor - ) { - JvmMethodGenericSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor); - Method asmMethod = signature.getAsmMethod(); - MethodVisitor mv = v.newMethod( - JvmDeclarationOriginKt.OtherOrigin(parameter, descriptor), - ACC_PUBLIC | ACC_ABSTRACT, - asmMethod.getName(), - asmMethod.getDescriptor(), - signature.getGenericsSignature(), - null - ); - - PropertyGetterDescriptor getter = descriptor.getGetter(); - assert getter != null : "Annotation property should have a getter: " + descriptor; - v.getSerializationBindings().put(METHOD_FOR_FUNCTION, getter, asmMethod); - AnnotationCodegen.forMethod(mv, memberCodegen, state).genAnnotations(getter, asmMethod.getReturnType(), null); - - KtExpression defaultValue = loadAnnotationArgumentDefaultValue(parameter, descriptor, expectedAnnotationConstructor); - if (defaultValue != null) { - ConstantValue constant = ExpressionCodegen.getCompileTimeConstant( - defaultValue, bindingContext, true, state.getShouldInlineConstVals()); - assert !state.getClassBuilderMode().generateBodies || constant != null - : "Default value for annotation parameter should be compile time value: " + defaultValue.getText(); - if (constant != null) { - AnnotationCodegen annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(mv, memberCodegen, state); - annotationCodegen.generateAnnotationDefaultValue(constant, descriptor.getType()); - } - } - - mv.visitEnd(); - } - - private KtExpression loadAnnotationArgumentDefaultValue( - @NotNull KtParameter ktParameter, - @NotNull PropertyDescriptor descriptor, - @Nullable FunctionDescriptor expectedAnnotationConstructor - ) { - KtExpression value = ktParameter.getDefaultValue(); - if (value != null) return value; - - if (expectedAnnotationConstructor != null) { - ValueParameterDescriptor expectedParameter = CollectionsKt.single( - expectedAnnotationConstructor.getValueParameters(), parameter -> parameter.getName().equals(descriptor.getName()) - ); - PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(expectedParameter); - if (!(element instanceof KtParameter)) { - state.getDiagnostics().report(EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND.on(ktParameter)); - return null; - } - return ((KtParameter) element).getDefaultValue(); - } - - return null; - } - - private void generateBackingField(@NotNull PropertyDescriptor descriptor, boolean isBackingFieldOwner) { - if (isJvmInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.DEFAULT_IMPLS || - kind == OwnerKind.ERASED_INLINE_CLASS) { - return; - } - - Object defaultValue; - if (descriptor.isDelegated()) { - defaultValue = null; - } - else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) { - if (shouldWriteFieldInitializer(descriptor)) { - ConstantValue initializer = descriptor.getCompileTimeInitializer(); - defaultValue = initializer == null ? null : initializer.getValue(); - } - else { - defaultValue = null; - } - } - else { - return; - } - - generateBackingField(descriptor, descriptor.isDelegated(), defaultValue, isBackingFieldOwner); - } - - // Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still - // accessible via reflection, and 'deprecated' and 'synthetic' flags prevent this method from being called accidentally - private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, boolean isBackingFieldOwner) { - Annotations annotations = descriptor.getAnnotations(); - if (annotations.isEmpty()) return; - - Method signature = typeMapper.mapSyntheticMethodForPropertyAnnotations(descriptor); - if (kind != OwnerKind.DEFAULT_IMPLS && CodegenContextUtil.isImplementationOwner(context, descriptor)) { - v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, signature); - } - - if (isBackingFieldOwner) { - if (!isInterface(context.getContextDescriptor()) || - processInterfaceMethod(descriptor, kind, false, true, state.getJvmDefaultMode())) { - memberCodegen.generateSyntheticAnnotationsMethod(descriptor, signature, annotations); - } - } - } - - private void generateBackingField( - @NotNull PropertyDescriptor propertyDescriptor, - boolean isDelegate, - @Nullable Object defaultValue, - boolean isBackingFieldOwner - ) { - FieldDescriptor annotatedField = isDelegate ? propertyDescriptor.getDelegateField() : propertyDescriptor.getBackingField(); - - int modifiers = getDeprecatedAccessFlag(propertyDescriptor); - - for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) { - modifiers |= flagAnnotation.getJvmFlag(annotatedField); - } - - if (kind == OwnerKind.PACKAGE) { - modifiers |= ACC_STATIC; - } - - if (!propertyDescriptor.isLateInit() && (!propertyDescriptor.isVar() || isDelegate)) { - modifiers |= ACC_FINAL; - } - - if (hasJvmSyntheticAnnotation(propertyDescriptor)) { - modifiers |= ACC_SYNTHETIC; - } - - KotlinType kotlinType = isDelegate ? getDelegateTypeForProperty(propertyDescriptor, bindingContext) : propertyDescriptor.getType(); - Type type = typeMapper.mapType(kotlinType); - - ClassBuilder builder = v; - - FieldOwnerContext backingFieldContext = context; - List additionalVisibleAnnotations = Collections.emptyList(); - if (DescriptorAsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) { - modifiers |= ACC_STATIC; - - if (DescriptorsJvmAbiUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) { - ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); - builder = codegen.v; - backingFieldContext = codegen.context; - if (DescriptorVisibilities.isPrivate(((ClassDescriptor) propertyDescriptor.getContainingDeclaration()).getVisibility())) { - modifiers |= ACC_DEPRECATED; - additionalVisibleAnnotations = Collections.singletonList(CodegenUtilKt.JAVA_LANG_DEPRECATED); - } - } - } - modifiers |= getVisibilityForBackingField(propertyDescriptor, isDelegate); - - if (DescriptorAsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) { - ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); - parentBodyCodegen.addCompanionObjectPropertyToCopy(propertyDescriptor, defaultValue); - } - - String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate); - - v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, new Pair<>(type, name)); - - if (isBackingFieldOwner) { - String signature = isDelegate ? null : typeMapper.mapFieldSignature(kotlinType, propertyDescriptor); - FieldVisitor fv = builder.newField( - JvmDeclarationOriginKt.OtherOrigin(propertyDescriptor), modifiers, name, type.getDescriptor(), - signature, defaultValue - ); - - if (annotatedField != null) { - // Don't emit nullability annotations for backing field if: - // - backing field is synthetic; - // - property is lateinit (since corresponding field is actually nullable). - boolean skipNullabilityAnnotations = - (modifiers & ACC_SYNTHETIC) != 0 || - propertyDescriptor.isLateInit(); - AnnotationCodegen.forField(fv, memberCodegen, state, skipNullabilityAnnotations) - .genAnnotations(annotatedField, type, propertyDescriptor.getType(), null, additionalVisibleAnnotations); - } - - if (propertyDescriptor.getContainingDeclaration() instanceof ClassDescriptor && JvmAnnotationUtilKt.isJvmRecord((ClassDescriptor) propertyDescriptor.getContainingDeclaration())) { - // builder.newRecordComponent(name, type.getDescriptor(), signature); - } - } - } - - @NotNull - public static KotlinType getDelegateTypeForProperty( - @NotNull PropertyDescriptor propertyDescriptor, - @NotNull BindingContext bindingContext - ) { - ResolvedCall provideDelegateResolvedCall = - bindingContext.get(BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor); - - KtProperty property = (KtProperty) DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor); - KtExpression delegateExpression = property != null ? property.getDelegateExpression() : null; - - KotlinType delegateType; - if (provideDelegateResolvedCall != null) { - delegateType = provideDelegateResolvedCall.getResultingDescriptor().getReturnType(); - } - else if (delegateExpression != null) { - delegateType = bindingContext.getType(delegateExpression); - } - else { - delegateType = null; - } - - if (delegateType == null) { - // Delegation convention is unresolved - delegateType = ErrorUtils.createErrorType("Delegate type"); - } - return delegateType; - } - - private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) { - if (!descriptor.isConst() && - state.getLanguageVersionSettings().supportsFeature(LanguageFeature.NoConstantValueAttributeForNonConstVals)) { - return false; - } - - //final field of primitive or String type - if (!descriptor.isVar()) { - Type type = typeMapper.mapType(descriptor); - return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName()); - } - return false; - } - - private void generateGetter(@NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor getter) { - generateAccessor( - getter, - descriptor.getGetter() != null ? descriptor.getGetter() : DescriptorFactory.createDefaultGetter( - descriptor, Annotations.Companion.getEMPTY() - ) - ); - } - - private void generateSetter(@NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor setter) { - if (!descriptor.isVar()) return; - - generateAccessor( - setter, - descriptor.getSetter() != null ? descriptor.getSetter() : DescriptorFactory.createDefaultSetter( - descriptor, Annotations.Companion.getEMPTY(), Annotations.Companion.getEMPTY() - ) - ); - } - - private void generateAccessor(@Nullable KtPropertyAccessor accessor, @NotNull PropertyAccessorDescriptor descriptor) { - if (context instanceof MultifileClassFacadeContext && - (DescriptorVisibilities.isPrivate(descriptor.getVisibility()) || - DescriptorAsmUtil.getVisibilityAccessFlag(descriptor) == Opcodes.ACC_PRIVATE)) { - return; - } - - FunctionGenerationStrategy strategy; - if (accessor == null || !accessor.hasBody()) { - if (descriptor.getCorrespondingProperty().isDelegated()) { - strategy = new DelegatedPropertyAccessorStrategy(state, descriptor); - } - else { - strategy = new DefaultPropertyAccessorStrategy(state, descriptor); - } - } - else { - strategy = new FunctionGenerationStrategy.FunctionDefault(state, accessor); - } - - functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), descriptor, strategy); - } - - private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased { - private final PropertyAccessorDescriptor propertyAccessorDescriptor; - - public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) { - super(state); - propertyAccessorDescriptor = descriptor; - } - - @Override - public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { - InstructionAdapter v = codegen.v; - PropertyDescriptor propertyDescriptor = propertyAccessorDescriptor.getCorrespondingProperty(); - StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0); - - PsiElement jetProperty = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor); - if (jetProperty instanceof KtProperty || jetProperty instanceof KtParameter) { - codegen.markLineNumber((KtElement) jetProperty, false); - } - - if (propertyAccessorDescriptor instanceof PropertyGetterDescriptor) { - Type type = signature.getReturnType(); - property.put(type, v); - v.areturn(type); - } - else if (propertyAccessorDescriptor instanceof PropertySetterDescriptor) { - List valueParameters = propertyAccessorDescriptor.getValueParameters(); - assert valueParameters.size() == 1 : "Property setter should have only one value parameter but has " + propertyAccessorDescriptor; - int parameterIndex = codegen.lookupLocalIndex(valueParameters.get(0)); - assert parameterIndex >= 0 : "Local index for setter parameter should be positive or zero: " + propertyAccessorDescriptor; - Type type = codegen.typeMapper.mapType(propertyDescriptor); - property.store(StackValue.local(parameterIndex, type), codegen.v); - v.visitInsn(RETURN); - } - else { - throw new IllegalStateException("Unknown property accessor: " + propertyAccessorDescriptor); - } - } - } - - public static StackValue invokeDelegatedPropertyConventionMethod( - @NotNull ExpressionCodegen codegen, - @NotNull ResolvedCall resolvedCall, - @NotNull StackValue receiver, - @NotNull PropertyDescriptor propertyDescriptor - ) { - codegen.tempVariables.put( - resolvedCall.getCall().getValueArguments().get(1).asElement(), - getDelegatedPropertyMetadata(propertyDescriptor, codegen.getBindingContext()) - ); - - return codegen.invokeFunction(resolvedCall, receiver); - } - - public static boolean isDelegatedPropertyWithOptimizedMetadata( - @NotNull VariableDescriptorWithAccessors descriptor, - @NotNull BindingContext bindingContext - ) { - return Boolean.TRUE == bindingContext.get(DELEGATED_PROPERTY_WITH_OPTIMIZED_METADATA, descriptor); - } - - public static @NotNull StackValue getOptimizedDelegatedPropertyMetadataValue() { - return StackValue.constant(null, K_PROPERTY_TYPE); - } - - @NotNull - public static StackValue getDelegatedPropertyMetadata( - @NotNull VariableDescriptorWithAccessors descriptor, - @NotNull BindingContext bindingContext - ) { - if (isDelegatedPropertyWithOptimizedMetadata(descriptor, bindingContext)) { - return getOptimizedDelegatedPropertyMetadataValue(); - } - - Type owner = bindingContext.get(DELEGATED_PROPERTY_METADATA_OWNER, descriptor); - assert owner != null : "Delegated property owner not found: " + descriptor; - - List allDelegatedProperties = bindingContext.get(DELEGATED_PROPERTIES_WITH_METADATA, owner); - int index = allDelegatedProperties == null ? -1 : allDelegatedProperties.indexOf(descriptor); - if (index < 0) { - throw new AssertionError("Delegated property not found in " + owner + ": " + descriptor); - } - - StackValue.Field array = StackValue.field( - Type.getType("[" + K_PROPERTY_TYPE), owner, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, true, StackValue.none() - ); - return StackValue.arrayElement(K_PROPERTY_TYPE, null, array, StackValue.constant(index)); - } - - private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased { - private final PropertyAccessorDescriptor propertyAccessorDescriptor; - - public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) { - super(state); - this.propertyAccessorDescriptor = descriptor; - } - - @Override - public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) { - InstructionAdapter v = codegen.v; - - BindingContext bindingContext = state.getBindingContext(); - ResolvedCall resolvedCall = - bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, propertyAccessorDescriptor); - assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString(); - - PropertyDescriptor propertyDescriptor = propertyAccessorDescriptor.getCorrespondingProperty(); - StackValue.Property property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0); - StackValue.Property delegate = property.getDelegateOrNull(); - assert delegate != null : "No delegate for delegated property: " + propertyDescriptor; - StackValue lastValue = invokeDelegatedPropertyConventionMethod(codegen, resolvedCall, delegate, propertyDescriptor); - Type asmType = signature.getReturnType(); - KotlinType kotlinReturnType = propertyAccessorDescriptor.getOriginal().getReturnType(); - lastValue.put(asmType, kotlinReturnType, v); - v.areturn(asmType); - } - } - - public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) { - ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration(); - - PropertyGetterDescriptor getter = delegate.getGetter(); - if (getter != null) { - //noinspection ConstantConditions - functionCodegen.genDelegate(getter, delegateTo.getGetter().getOriginal(), toClass, field); - } - - PropertySetterDescriptor setter = delegate.getSetter(); - if (setter != null) { - //noinspection ConstantConditions - functionCodegen.genDelegate(setter, delegateTo.getSetter().getOriginal(), toClass, field); - } - } -} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JavaLanguageLevel.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JavaLanguageLevel.kt new file mode 100644 index 00000000000..b14569fb5fc --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JavaLanguageLevel.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.cli.jvm.compiler + +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.LanguageLevelProjectExtension +import com.intellij.pom.java.LanguageLevel + +fun Project.setupHighestLanguageLevel() { + LanguageLevelProjectExtension.getInstance(this).languageLevel = LanguageLevel.JDK_15_PREVIEW +} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JavaLanguageLevel.kt.201 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JavaLanguageLevel.kt.201 new file mode 100644 index 00000000000..423b6b10229 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JavaLanguageLevel.kt.201 @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.cli.jvm.compiler + +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.LanguageLevelProjectExtension +import com.intellij.pom.java.LanguageLevel + +fun Project.setupHighestLanguageLevel() { + // LanguageLevelProjectExtension.getInstance(this).languageLevel = LanguageLevel.JDK_15_PREVIEW +} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index 47c6ee66a30..dc9270e9345 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -253,7 +253,7 @@ class KotlinCoreEnvironment private constructor( updateClasspath(roots.map { JavaSourceRoot(it, null) }) }) - LanguageLevelProjectExtension.getInstance(project).languageLevel = LanguageLevel.JDK_15_PREVIEW + project.setupHighestLanguageLevel() } private fun collectAdditionalSources(project: MockProject) { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt.201 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt.201 deleted file mode 100644 index 6120985d6ce..00000000000 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt.201 +++ /dev/null @@ -1,703 +0,0 @@ -/* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.cli.jvm.compiler - -import com.intellij.codeInsight.ExternalAnnotationsManager -import com.intellij.codeInsight.InferredAnnotationsManager -import com.intellij.core.CoreApplicationEnvironment -import com.intellij.core.CoreJavaFileManager -import com.intellij.core.JavaCoreProjectEnvironment -import com.intellij.ide.highlighter.JavaFileType -import com.intellij.lang.java.JavaParserDefinition -import com.intellij.mock.MockProject -import com.intellij.openapi.Disposable -import com.intellij.openapi.application.TransactionGuard -import com.intellij.openapi.application.TransactionGuardImpl -import com.intellij.openapi.components.ServiceManager -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.extensions.Extensions -import com.intellij.openapi.extensions.ExtensionsArea -import com.intellij.openapi.fileTypes.PlainTextFileType -import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.LanguageLevelProjectExtension -import com.intellij.openapi.util.Disposer -import com.intellij.openapi.util.io.FileUtilRt -import com.intellij.openapi.util.text.StringUtil -import com.intellij.openapi.vfs.* -import com.intellij.openapi.vfs.impl.ZipHandler -import com.intellij.pom.java.LanguageLevel -import com.intellij.psi.PsiElementFinder -import com.intellij.psi.PsiManager -import com.intellij.psi.compiled.ClassFileDecompilers -import com.intellij.psi.impl.JavaClassSupersImpl -import com.intellij.psi.impl.PsiElementFinderImpl -import com.intellij.psi.impl.PsiTreeChangePreprocessor -import com.intellij.psi.impl.file.impl.JavaFileManager -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.util.JavaClassSupers -import com.intellij.util.io.URLUtil -import com.intellij.util.lang.UrlClassLoader -import org.jetbrains.annotations.TestOnly -import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport -import org.jetbrains.kotlin.asJava.LightClassGenerationSupport -import org.jetbrains.kotlin.asJava.classes.FacadeCache -import org.jetbrains.kotlin.asJava.finder.JavaElementFinder -import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension -import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys -import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl -import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY -import org.jetbrains.kotlin.cli.common.config.ContentRoot -import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot -import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots -import org.jetbrains.kotlin.cli.common.extensions.ScriptEvaluationExtension -import org.jetbrains.kotlin.cli.common.extensions.ShellExtension -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.common.toBooleanLenient -import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker -import org.jetbrains.kotlin.cli.jvm.config.* -import org.jetbrains.kotlin.cli.jvm.index.* -import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar -import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder -import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleResolver -import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem -import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension -import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension -import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar -import org.jetbrains.kotlin.config.* -import org.jetbrains.kotlin.extensions.* -import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor -import org.jetbrains.kotlin.extensions.internal.TypeResolutionInterceptor -import org.jetbrains.kotlin.idea.KotlinFileType -import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension -import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache -import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory -import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager -import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory -import org.jetbrains.kotlin.parsing.KotlinParserDefinition -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer -import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver -import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension -import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension -import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade -import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension -import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension -import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver -import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService -import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService -import org.jetbrains.kotlin.serialization.DescriptorSerializerPlugin -import org.jetbrains.kotlin.utils.PathUtil -import java.io.File -import java.nio.file.FileSystems -import java.util.zip.ZipFile - -class KotlinCoreEnvironment private constructor( - val projectEnvironment: JavaCoreProjectEnvironment, - private val initialConfiguration: CompilerConfiguration, - configFiles: EnvironmentConfigFiles -) { - - class ProjectEnvironment( - disposable: Disposable, - applicationEnvironment: KotlinCoreApplicationEnvironment - ) : - KotlinCoreProjectEnvironment(disposable, applicationEnvironment) { - - private var extensionRegistered = false - - override fun preregisterServices() { - registerProjectExtensionPoints(project.extensionArea) - } - - fun registerExtensionsFromPlugins(configuration: CompilerConfiguration) { - if (!extensionRegistered) { - registerPluginExtensionPoints(project) - registerExtensionsFromPlugins(project, configuration) - extensionRegistered = true - } - } - - override fun registerJavaPsiFacade() { - with(project) { - registerService( - CoreJavaFileManager::class.java, - ServiceManager.getService(this, JavaFileManager::class.java) as CoreJavaFileManager - ) - - registerKotlinLightClassSupport(project) - - registerService(ExternalAnnotationsManager::class.java, MockExternalAnnotationsManager()) - registerService(InferredAnnotationsManager::class.java, MockInferredAnnotationsManager()) - } - - super.registerJavaPsiFacade() - } - } - - private val sourceFiles = mutableListOf() - private val rootsIndex: JvmDependenciesDynamicCompoundIndex - private val packagePartProviders = mutableListOf() - - private val classpathRootsResolver: ClasspathRootsResolver - private val initialRoots = ArrayList() - - val configuration: CompilerConfiguration = initialConfiguration.apply { setupJdkClasspathRoots(configFiles) }.copy() - - init { - PersistentFSConstants::class.java.getDeclaredField("ourMaxIntellisenseFileSize") - .apply { isAccessible = true } - .setInt(null, FileUtilRt.LARGE_FOR_CONTENT_LOADING) - - val project = projectEnvironment.project - - val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) - - (projectEnvironment as? ProjectEnvironment)?.registerExtensionsFromPlugins(configuration) - // otherwise consider that project environment is properly configured before passing to the environment - // TODO: consider some asserts to check important extension points - - project.registerService(DeclarationProviderFactoryService::class.java, CliDeclarationProviderFactoryService(sourceFiles)) - - val isJvm = configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES - project.registerService(ModuleVisibilityManager::class.java, CliModuleVisibilityManagerImpl(isJvm)) - - registerProjectServicesForCLI(projectEnvironment) - - registerProjectServices(projectEnvironment.project) - - for (extension in CompilerConfigurationExtension.getInstances(project)) { - extension.updateConfiguration(configuration) - } - - sourceFiles += createKtFiles(project) - - collectAdditionalSources(project) - - sourceFiles.sortBy { it.virtualFile.path } - - val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME) - val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL) - val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path -> - jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR) - }) - - val outputDirectory = - configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory() - ?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)?.absolutePath - - classpathRootsResolver = ClasspathRootsResolver( - PsiManager.getInstance(project), - messageCollector, - configuration.getList(JVMConfigurationKeys.ADDITIONAL_JAVA_MODULES), - this::contentRootToVirtualFile, - javaModuleFinder, - !configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE), - outputDirectory?.let(this::findLocalFile) - ) - - val (initialRoots, javaModules) = - classpathRootsResolver.convertClasspathRoots(configuration.getList(CLIConfigurationKeys.CONTENT_ROOTS)) - this.initialRoots.addAll(initialRoots) - - if (!configuration.getBoolean(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK) && messageCollector != null) { - JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency( - messageCollector, - configuration, - initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null } - ) - } - - val (roots, singleJavaFileRoots) = - initialRoots.partition { (file) -> file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION } - - // REPL and kapt2 update classpath dynamically - rootsIndex = JvmDependenciesDynamicCompoundIndex().apply { - addIndex(JvmDependenciesIndexImpl(roots)) - updateClasspathFromRootsIndex(this) - } - - (ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl).initialize( - rootsIndex, - packagePartProviders, - SingleJavaFileRootsIndex(singleJavaFileRoots), - configuration.getBoolean(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING) - ) - - project.registerService( - JavaModuleResolver::class.java, - CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList()) - ) - - val finderFactory = CliVirtualFileFinderFactory(rootsIndex) - project.registerService(MetadataFinderFactory::class.java, finderFactory) - project.registerService(VirtualFileFinderFactory::class.java, finderFactory) - - project.putUserData(APPEND_JAVA_SOURCE_ROOTS_HANDLER_KEY, fun(roots: List) { - updateClasspath(roots.map { JavaSourceRoot(it, null) }) - }) - } - - private fun collectAdditionalSources(project: MockProject) { - var unprocessedSources: Collection = sourceFiles - val processedSources = HashSet() - val processedSourcesByExtension = HashMap>() - // repeat feeding extensions with sources while new sources a being added - var sourceCollectionIterations = 0 - while (unprocessedSources.isNotEmpty()) { - if (sourceCollectionIterations++ > 10) { // TODO: consider using some appropriate global constant - throw IllegalStateException("Unable to collect additional sources in reasonable number of iterations") - } - processedSources.addAll(unprocessedSources) - val allNewSources = ArrayList() - for (extension in CollectAdditionalSourcesExtension.getInstances(project)) { - // do not feed the extension with the sources it returned on the previous iteration - val sourcesToProcess = unprocessedSources - (processedSourcesByExtension[extension] ?: emptyList()) - val newSources = extension.collectAdditionalSourcesAndUpdateConfiguration(sourcesToProcess, configuration, project) - if (newSources.isNotEmpty()) { - allNewSources.addAll(newSources) - processedSourcesByExtension[extension] = newSources - } - } - unprocessedSources = allNewSources.filterNot { processedSources.contains(it) }.distinct() - sourceFiles += unprocessedSources - } - } - - fun addKotlinSourceRoots(rootDirs: List) { - val roots = rootDirs.map { KotlinSourceRoot(it.absolutePath, isCommon = false) } - sourceFiles += createSourceFilesFromSourceRoots(configuration, project, roots) - } - - fun createPackagePartProvider(scope: GlobalSearchScope): JvmPackagePartProvider { - return JvmPackagePartProvider(configuration.languageVersionSettings, scope).apply { - addRoots(initialRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)) - packagePartProviders += this - (ModuleAnnotationsResolver.getInstance(project) as CliModuleAnnotationsResolver).addPackagePartProvider(this) - } - } - - private val VirtualFile.javaFiles: List - get() = mutableListOf().apply { - VfsUtilCore.processFilesRecursively(this@javaFiles) { file -> - if (file.fileType == JavaFileType.INSTANCE) { - add(file) - } - true - } - } - - private val allJavaFiles: List - get() = configuration.javaSourceRoots - .mapNotNull(this::findLocalFile) - .flatMap { it.javaFiles } - .map { File(it.canonicalPath) } - - fun registerJavac( - javaFiles: List = allJavaFiles, - kotlinFiles: List = sourceFiles, - arguments: Array? = null, - bootClasspath: List? = null, - sourcePath: List? = null - ): Boolean { - return JavacWrapperRegistrar.registerJavac( - projectEnvironment.project, configuration, javaFiles, kotlinFiles, arguments, bootClasspath, sourcePath, - LightClassGenerationSupport.getInstance(project), packagePartProviders - ) - } - - private val applicationEnvironment: CoreApplicationEnvironment - get() = projectEnvironment.environment - - val project: Project - get() = projectEnvironment.project - - internal fun countLinesOfCode(sourceFiles: List): Int = - sourceFiles.sumBy { sourceFile -> - val text = sourceFile.text - StringUtil.getLineBreakCount(text) + (if (StringUtil.endsWithLineBreak(text)) 0 else 1) - } - - private fun updateClasspathFromRootsIndex(index: JvmDependenciesIndex) { - index.indexedRoots.forEach { - projectEnvironment.addSourcesToClasspath(it.file) - } - } - - fun updateClasspath(contentRoots: List): List? { - // TODO: add new Java modules to CliJavaModuleResolver - val newRoots = classpathRootsResolver.convertClasspathRoots(contentRoots).roots - - if (packagePartProviders.isEmpty()) { - initialRoots.addAll(newRoots) - } else { - for (packagePartProvider in packagePartProviders) { - packagePartProvider.addRoots(newRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)) - } - } - - return rootsIndex.addNewIndexForRoots(newRoots)?.let { newIndex -> - updateClasspathFromRootsIndex(newIndex) - newIndex.indexedRoots.mapNotNull { (file) -> - VfsUtilCore.virtualToIoFile(VfsUtilCore.getVirtualFileForJar(file) ?: file) - }.toList() - }.orEmpty() - } - - private fun contentRootToVirtualFile(root: JvmContentRoot): VirtualFile? = - when (root) { - is JvmClasspathRoot -> - if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Classpath entry") - is JvmModulePathRoot -> - if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Java module root") - is JavaSourceRoot -> - findExistingRoot(root, "Java source root") - else -> - throw IllegalStateException("Unexpected root: $root") - } - - internal fun findLocalFile(path: String): VirtualFile? = - applicationEnvironment.localFileSystem.findFileByPath(path) - - private fun findExistingRoot(root: JvmContentRoot, rootDescription: String): VirtualFile? { - return findLocalFile(root.file.absolutePath).also { - if (it == null) { - report(STRONG_WARNING, "$rootDescription points to a non-existent location: ${root.file}") - } - } - } - - private fun findJarRoot(file: File): VirtualFile? = - applicationEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}") - - private fun getSourceRootsCheckingForDuplicates(): List { - val uniqueSourceRoots = hashSetOf() - val result = mutableListOf() - - for (root in configuration.kotlinSourceRoots) { - if (!uniqueSourceRoots.add(root.path)) { - report(STRONG_WARNING, "Duplicate source root: ${root.path}") - } - result.add(root) - } - - return result - } - - fun getSourceFiles(): List = sourceFiles - - private fun createKtFiles(project: Project): List = - createSourceFilesFromSourceRoots(configuration, project, getSourceRootsCheckingForDuplicates()) - - internal fun report(severity: CompilerMessageSeverity, message: String) = configuration.report(severity, message) - - companion object { - private val LOG = Logger.getInstance(KotlinCoreEnvironment::class.java) - - private val APPLICATION_LOCK = Object() - private var ourApplicationEnvironment: KotlinCoreApplicationEnvironment? = null - private var ourProjectCount = 0 - - @JvmStatic - fun createForProduction( - parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles - ): KotlinCoreEnvironment { - setupIdeaStandaloneExecution() - val appEnv = getOrCreateApplicationEnvironmentForProduction(parentDisposable, configuration) - val projectEnv = ProjectEnvironment(parentDisposable, appEnv) - val environment = KotlinCoreEnvironment(projectEnv, configuration, configFiles) - - synchronized(APPLICATION_LOCK) { - ourProjectCount++ - } - return environment - } - - @JvmStatic - fun createForProduction( - projectEnvironment: JavaCoreProjectEnvironment, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles - ): KotlinCoreEnvironment { - val environment = KotlinCoreEnvironment(projectEnvironment, configuration, configFiles) - - if (projectEnvironment.environment == applicationEnvironment) { - // accounting for core environment disposing - synchronized(APPLICATION_LOCK) { - ourProjectCount++ - } - } - return environment - } - - @TestOnly - @JvmStatic - fun createForTests( - parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles - ): KotlinCoreEnvironment { - val configuration = initialConfiguration.copy() - // Tests are supposed to create a single project and dispose it right after use - val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true) - val projectEnv = ProjectEnvironment(parentDisposable, appEnv) - return KotlinCoreEnvironment(projectEnv, configuration, extensionConfigs) - } - - // used in the daemon for jar cache cleanup - val applicationEnvironment: KotlinCoreApplicationEnvironment? get() = ourApplicationEnvironment - - fun getOrCreateApplicationEnvironmentForProduction( - parentDisposable: Disposable, configuration: CompilerConfiguration - ): KotlinCoreApplicationEnvironment { - synchronized(APPLICATION_LOCK) { - if (ourApplicationEnvironment == null) { - val disposable = Disposer.newDisposable() - ourApplicationEnvironment = createApplicationEnvironment(disposable, configuration, unitTestMode = false) - ourProjectCount = 0 - Disposer.register(disposable, Disposable { - synchronized(APPLICATION_LOCK) { - ourApplicationEnvironment = null - } - }) - } - // Disposing of the environment is unsafe in production then parallel builds are enabled, but turning it off universally - // breaks a lot of tests, therefore it is disabled for production and enabled for tests - if (System.getProperty(KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY).toBooleanLenient() != true) { - // JPS may run many instances of the compiler in parallel (there's an option for compiling independent modules in parallel in IntelliJ) - // All projects share the same ApplicationEnvironment, and when the last project is disposed, the ApplicationEnvironment is disposed as well - @Suppress("ObjectLiteralToLambda") // Disposer tree depends on identity of disposables. - Disposer.register(parentDisposable, object : Disposable { - override fun dispose() { - synchronized(APPLICATION_LOCK) { - if (--ourProjectCount <= 0) { - disposeApplicationEnvironment() - } - } - } - }) - } - - return ourApplicationEnvironment!! - } - } - - /** - * This method is also used in Gradle after configuration phase finished. - */ - fun disposeApplicationEnvironment() { - synchronized(APPLICATION_LOCK) { - val environment = ourApplicationEnvironment ?: return - ourApplicationEnvironment = null - Disposer.dispose(environment.parentDisposable) - ZipHandler.clearFileAccessorCache() - } - } - - private fun createApplicationEnvironment( - parentDisposable: Disposable, configuration: CompilerConfiguration, unitTestMode: Boolean - ): KotlinCoreApplicationEnvironment { - val applicationEnvironment = KotlinCoreApplicationEnvironment.create(parentDisposable, unitTestMode) - - registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/compiler.xml") - // FIX ME WHEN BUNCH 202 REMOVED: this code is required to support compiler bundled to both 202 and 203. - // Please, remove "com.intellij.psi.classFileDecompiler" EP registration once 202 is no longer supported by the compiler - if (!Extensions.getRootArea().hasExtensionPoint("com.intellij.psi.classFileDecompiler")) { - registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/core.xml") - } - - registerApplicationServicesForCLI(applicationEnvironment) - registerApplicationServices(applicationEnvironment) - - return applicationEnvironment - } - - private fun registerApplicationExtensionPointsAndExtensionsFrom(configuration: CompilerConfiguration, configFilePath: String) { - fun File.hasConfigFile(configFile: String): Boolean = - if (isDirectory) File(this, "META-INF" + File.separator + configFile).exists() - else try { - ZipFile(this).use { - it.getEntry("META-INF/$configFile") != null - } - } catch (e: Throwable) { - false - } - - val pluginRoot: File = - configuration.get(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT)?.let(::File) - ?: PathUtil.getResourcePathForClass(this::class.java).takeIf { it.hasConfigFile(configFilePath) } - // hack for load extensions when compiler run directly from project directory (e.g. in tests) - ?: File("compiler/cli/cli-common/resources").takeIf { it.hasConfigFile(configFilePath) } - ?: throw IllegalStateException( - "Unable to find extension point configuration $configFilePath " + - "(cp:\n ${(Thread.currentThread().contextClassLoader as? UrlClassLoader)?.urls?.joinToString("\n ") { it.file }})" - ) - - CoreApplicationEnvironment.registerExtensionPointAndExtensions( - FileSystems.getDefault().getPath(pluginRoot.path), - configFilePath, - Extensions.getRootArea() - ) - } - - @JvmStatic - @Suppress("MemberVisibilityCanPrivate") // made public for CLI Android Lint - fun registerPluginExtensionPoints(project: MockProject) { - ExpressionCodegenExtension.registerExtensionPoint(project) - SyntheticResolveExtension.registerExtensionPoint(project) - ClassBuilderInterceptorExtension.registerExtensionPoint(project) - AnalysisHandlerExtension.registerExtensionPoint(project) - PackageFragmentProviderExtension.registerExtensionPoint(project) - StorageComponentContainerContributor.registerExtensionPoint(project) - DeclarationAttributeAltererExtension.registerExtensionPoint(project) - PreprocessedVirtualFileFactoryExtension.registerExtensionPoint(project) - JsSyntheticTranslateExtension.registerExtensionPoint(project) - CompilerConfigurationExtension.registerExtensionPoint(project) - CollectAdditionalSourcesExtension.registerExtensionPoint(project) - ExtraImportsProviderExtension.registerExtensionPoint(project) - IrGenerationExtension.registerExtensionPoint(project) - ScriptEvaluationExtension.registerExtensionPoint(project) - ShellExtension.registerExtensionPoint(project) - TypeResolutionInterceptor.registerExtensionPoint(project) - CandidateInterceptor.registerExtensionPoint(project) - DescriptorSerializerPlugin.registerExtensionPoint(project) - } - - internal fun registerExtensionsFromPlugins(project: MockProject, configuration: CompilerConfiguration) { - val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) - for (registrar in configuration.getList(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS)) { - try { - registrar.registerProjectComponents(project, configuration) - } catch (e: AbstractMethodError) { - val message = "The provided plugin ${registrar.javaClass.name} is not compatible with this version of compiler" - // Since the scripting plugin is often discovered in the compiler environment, it is often taken from the incompatible - // location, and in many cases this is not a fatal error, therefore strong warning is generated instead of exception - if (registrar.javaClass.simpleName == "ScriptingCompilerConfigurationComponentRegistrar") { - messageCollector?.report(STRONG_WARNING, "Default scripting plugin is disabled: $message") - } else { - throw IllegalStateException(message, e) - } - } - } - } - - - private fun registerApplicationServicesForCLI(applicationEnvironment: KotlinCoreApplicationEnvironment) { - // ability to get text from annotations xml files - applicationEnvironment.registerFileType(PlainTextFileType.INSTANCE, "xml") - applicationEnvironment.registerParserDefinition(JavaParserDefinition()) - } - - // made public for Upsource - @Suppress("MemberVisibilityCanBePrivate") - @JvmStatic - fun registerApplicationServices(applicationEnvironment: KotlinCoreApplicationEnvironment) { - with(applicationEnvironment) { - registerFileType(KotlinFileType.INSTANCE, "kt") - registerFileType(KotlinFileType.INSTANCE, KotlinParserDefinition.STD_SCRIPT_SUFFIX) - registerParserDefinition(KotlinParserDefinition()) - application.registerService(KotlinBinaryClassCache::class.java, KotlinBinaryClassCache()) - application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java) - application.registerService(TransactionGuard::class.java, TransactionGuardImpl::class.java) - } - } - - @JvmStatic - fun registerProjectExtensionPoints(area: ExtensionsArea) { - CoreApplicationEnvironment.registerExtensionPoint( - area, PsiTreeChangePreprocessor.EP.name, PsiTreeChangePreprocessor::class.java - ) - CoreApplicationEnvironment.registerExtensionPoint(area, PsiElementFinder.EP.name, PsiElementFinder::class.java) - - IdeaExtensionPoints.registerVersionSpecificProjectExtensionPoints(area) - } - - // made public for Upsource - @JvmStatic - @Deprecated("Use registerProjectServices(project) instead.", ReplaceWith("registerProjectServices(projectEnvironment.project)")) - fun registerProjectServices( - projectEnvironment: JavaCoreProjectEnvironment, - @Suppress("UNUSED_PARAMETER") messageCollector: MessageCollector? - ) { - registerProjectServices(projectEnvironment.project) - } - - // made public for Android Lint - @JvmStatic - fun registerProjectServices(project: MockProject) { - with(project) { - registerService(KotlinJavaPsiFacade::class.java, KotlinJavaPsiFacade(this)) - registerService(FacadeCache::class.java, FacadeCache(this)) - registerService(ModuleAnnotationsResolver::class.java, CliModuleAnnotationsResolver()) - } - } - - private fun registerProjectServicesForCLI(@Suppress("UNUSED_PARAMETER") projectEnvironment: JavaCoreProjectEnvironment) { - /** - * Note that Kapt may restart code analysis process, and CLI services should be aware of that. - * Use PsiManager.getModificationTracker() to ensure that all the data you cached is still valid. - */ - } - - // made public for Android Lint - @JvmStatic - fun registerKotlinLightClassSupport(project: MockProject) { - with(project) { - val traceHolder = CliTraceHolder() - val cliLightClassGenerationSupport = CliLightClassGenerationSupport(traceHolder, project) - val kotlinAsJavaSupport = CliKotlinAsJavaSupport(this, traceHolder) - registerService(LightClassGenerationSupport::class.java, cliLightClassGenerationSupport) - registerService(CliLightClassGenerationSupport::class.java, cliLightClassGenerationSupport) - registerService(KotlinAsJavaSupport::class.java, kotlinAsJavaSupport) - registerService(CodeAnalyzerInitializer::class.java, traceHolder) - - // We don't pass Disposable because in some tests, we manually unregister these extensions, and that leads to LOG.error - // exception from `ExtensionPointImpl.doRegisterExtension`, because the registered extension can no longer be found - // when the project is being disposed. - // For example, see the `unregisterExtension` call in `GenerationUtils.compileFilesUsingFrontendIR`. - // TODO: refactor this to avoid registering unneeded extensions in the first place, and avoid using deprecated API. - @Suppress("DEPRECATION") - PsiElementFinder.EP.getPoint(project).registerExtension(JavaElementFinder(this, kotlinAsJavaSupport)) - @Suppress("DEPRECATION") - PsiElementFinder.EP.getPoint(project).registerExtension(PsiElementFinderImpl(this)) - } - } - - private fun CompilerConfiguration.setupJdkClasspathRoots(configFiles: EnvironmentConfigFiles) { - if (getBoolean(JVMConfigurationKeys.NO_JDK)) return - - val jvmTarget = configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES - if (!jvmTarget) return - - val jdkHome = get(JVMConfigurationKeys.JDK_HOME) - val (javaRoot, classesRoots) = if (jdkHome == null) { - val javaHome = File(System.getProperty("java.home")) - put(JVMConfigurationKeys.JDK_HOME, javaHome) - - javaHome to PathUtil.getJdkClassesRootsFromCurrentJre() - } else { - jdkHome to PathUtil.getJdkClassesRoots(jdkHome) - } - - if (!CoreJrtFileSystem.isModularJdk(javaRoot)) { - if (classesRoots.isEmpty()) { - report(ERROR, "No class roots are found in the JDK path: $javaRoot") - } else { - addJvmSdkRoots(classesRoots) - } - } - } - } -} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index 2fbfafdef6c..9f722783158 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -10,9 +10,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField import org.jetbrains.kotlin.backend.jvm.lower.hasAssertionsDisabledField -import org.jetbrains.kotlin.codegen.DescriptorAsmUtil +import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.inline.* -import org.jetbrains.kotlin.codegen.writeKotlinMetadata import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.DescriptorVisibilities @@ -309,7 +308,7 @@ class ClassCodegen private constructor( if (irClass.hasAnnotation(JVM_RECORD_ANNOTATION_FQ_NAME) && !field.isStatic) { // TODO: Write annotations to the component - visitor.newRecordComponent(fieldName, fieldType.descriptor, fieldSignature) + visitor.addRecordComponent(fieldName, fieldType.descriptor, fieldSignature) } } @@ -457,7 +456,7 @@ private val IrClass.flags: Int isAnnotationClass -> Opcodes.ACC_ANNOTATION or Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT isInterface -> Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT isEnumClass -> Opcodes.ACC_ENUM or Opcodes.ACC_SUPER or modality.flags - hasAnnotation(JVM_RECORD_ANNOTATION_FQ_NAME) -> Opcodes.ACC_RECORD or Opcodes.ACC_SUPER or modality.flags + hasAnnotation(JVM_RECORD_ANNOTATION_FQ_NAME) -> VersionIndependentOpcodes.ACC_RECORD or Opcodes.ACC_SUPER or modality.flags else -> Opcodes.ACC_SUPER or modality.flags } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt.201 b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt.201 deleted file mode 100644 index 8681265cd40..00000000000 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt.201 +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.backend.jvm.codegen - -import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin -import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry -import org.jetbrains.kotlin.backend.jvm.lower.buildAssertionsDisabledField -import org.jetbrains.kotlin.backend.jvm.lower.hasAssertionsDisabledField -import org.jetbrains.kotlin.codegen.DescriptorAsmUtil -import org.jetbrains.kotlin.codegen.inline.* -import org.jetbrains.kotlin.codegen.writeKotlinMetadata -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.descriptors.DescriptorVisibility -import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.ir.builders.declarations.addFunction -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor -import org.jetbrains.kotlin.ir.expressions.IrBlockBody -import org.jetbrains.kotlin.ir.expressions.IrConst -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl -import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.load.java.JvmAnnotationNames -import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader -import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.protobuf.MessageLite -import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_RECORD_ANNOTATION_FQ_NAME -import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME -import org.jetbrains.kotlin.resolve.jvm.annotations.TRANSIENT_ANNOTATION_FQ_NAME -import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME -import org.jetbrains.kotlin.resolve.jvm.checkers.JvmSimpleNameBacktickChecker -import org.jetbrains.kotlin.resolve.jvm.diagnostics.* -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull -import org.jetbrains.kotlin.utils.addToStdlib.safeAs -import org.jetbrains.org.objectweb.asm.* -import org.jetbrains.org.objectweb.asm.commons.Method -import org.jetbrains.org.objectweb.asm.tree.MethodNode -import java.io.File - -interface MetadataSerializer { - fun serialize(metadata: MetadataSource): Pair? - fun bindMethodMetadata(metadata: MetadataSource.Property, signature: Method) - fun bindMethodMetadata(metadata: MetadataSource.Function, signature: Method) - fun bindFieldMetadata(metadata: MetadataSource.Property, signature: Pair) -} - -class ClassCodegen private constructor( - val irClass: IrClass, - val context: JvmBackendContext, - private val parentFunction: IrFunction?, -) : InnerClassConsumer { - private val parentClassCodegen = (parentFunction?.parentAsClass ?: irClass.parent as? IrClass)?.let { getOrCreate(it, context) } - private val withinInline: Boolean = parentClassCodegen?.withinInline == true || parentFunction?.isInline == true - - private val state get() = context.state - private val typeMapper get() = context.typeMapper - - val type: Type = typeMapper.mapClass(irClass) - - val reifiedTypeParametersUsages = ReifiedTypeParametersUsages() - - private val jvmSignatureClashDetector = JvmSignatureClashDetector(irClass, type, context) - - private val classOrigin = irClass.descriptorOrigin - - private val visitor = state.factory.newVisitor(classOrigin, type, irClass.fileParent.loadSourceFilesInfo()).apply { - val signature = typeMapper.mapClassSignature(irClass, type) - // Ensure that the backend only produces class names that would be valid in the frontend for JVM. - if (context.state.classBuilderMode.generateBodies && signature.hasInvalidName()) { - throw IllegalStateException("Generating class with invalid name '${type.className}': ${irClass.dump()}") - } - defineClass( - irClass.psiElement, - state.classFileVersion, - irClass.flags, - signature.name, - signature.javaGenericSignature, - signature.superclassName, - signature.interfaces.toTypedArray() - ) - } - - // TODO: the order of entries in this set depends on the order in which methods are generated; this means it is unstable - // under incremental compilation, as calls to `inline fun`s declared in this class cause them to be generated out of order. - private val innerClasses = linkedSetOf() - - // TODO: the names produced by generators in this map depend on the order in which methods are generated; see above. - private val regeneratedObjectNameGenerators = mutableMapOf() - - fun getRegeneratedObjectNameGenerator(function: IrFunction): NameGenerator { - val name = if (function.name.isSpecial) "special" else function.name.asString() - return regeneratedObjectNameGenerators.getOrPut(name) { - NameGenerator("${type.internalName}\$$name\$\$inlined") - } - } - - private var generated = false - - fun generate() { - // TODO: reject repeated generate() calls; currently, these can happen for objects in finally - // blocks since they are `accept`ed once per each CFG edge out of the try-finally. - if (generated) return - generated = true - - // We remove reads of `$$delegatedProperties` (and the field itself) if they are not in fact used for anything. - val delegatedProperties = irClass.fields.singleOrNull { it.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE } - val delegatedPropertyOptimizer = if (delegatedProperties != null) DelegatedPropertyOptimizer() else null - // Generating a method node may cause the addition of a field with an initializer if an inline function - // call uses `assert` and the JVM assertions mode is enabled. To avoid concurrent modification errors, - // there is a very specific generation order. - val smap = context.getSourceMapper(irClass) - // 1. Any method other than `` can add a field and a `` statement: - for (method in irClass.declarations.filterIsInstance()) { - if (method.name.asString() != "") { - generateMethod(method, smap, delegatedPropertyOptimizer) - } - } - // 2. `` itself can add a field, but the statement is generated via the `return init` hack: - irClass.functions.find { it.name.asString() == "" }?.let { generateMethod(it, smap, delegatedPropertyOptimizer) } - // 3. Now we have all the fields (`$$delegatedProperties` might be redundant if all reads were optimized out): - for (field in irClass.fields) { - if (field !== delegatedProperties || delegatedPropertyOptimizer?.needsDelegatedProperties == true) { - generateField(field) - } - } - // 4. Generate nested classes at the end, to ensure that when the companion's metadata is serialized - // everything moved to the outer class has already been recorded in `globalSerializationBindings`. - for (declaration in irClass.declarations) { - if (declaration is IrClass) { - getOrCreate(declaration, context).generate() - } - } - - object : AnnotationCodegen(this@ClassCodegen, context) { - override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor { - return visitor.visitor.visitAnnotation(descr, visible) - } - }.genAnnotations(irClass, null, null) - generateKotlinMetadataAnnotation() - - generateInnerAndOuterClasses() - - if (withinInline || !smap.isTrivial) { - visitor.visitSMAP(smap, !context.state.languageVersionSettings.supportsFeature(LanguageFeature.CorrectSourceMappingSyntax)) - } else { - smap.sourceInfo!!.sourceFileName?.let { - visitor.visitSource(it, null) - } - } - - visitor.done() - jvmSignatureClashDetector.reportErrors(classOrigin) - } - - fun generateAssertFieldIfNeeded(generatingClInit: Boolean): IrExpression? { - if (irClass.hasAssertionsDisabledField(context)) - return null - val topLevelClass = generateSequence(this) { it.parentClassCodegen }.last().irClass - val field = irClass.buildAssertionsDisabledField(context, topLevelClass) - generateField(field) - // Normally, `InitializersLowering` would move the initializer to , but - // it's obviously too late for that. - val init = IrSetFieldImpl( - field.startOffset, field.endOffset, field.symbol, null, - field.initializer!!.expression, context.irBuiltIns.unitType - ) - if (generatingClInit) { - // Too late to modify the IR; have to ask the currently active `ExpressionCodegen` - // to generate this statement directly. - return init - } - val classInitializer = irClass.functions.singleOrNull { it.name.asString() == "" } ?: irClass.addFunction { - name = Name.special("") - returnType = context.irBuiltIns.unitType - }.apply { - body = IrBlockBodyImpl(startOffset, endOffset) - } - (classInitializer.body as IrBlockBody).statements.add(0, init) - return null - } - - private val metadataSerializer: MetadataSerializer = - context.backendExtension.createSerializer( - context, irClass, type, visitor.serializationBindings, parentClassCodegen?.metadataSerializer - ) - - private fun generateKotlinMetadataAnnotation() { - // TODO: if `-Xmultifile-parts-inherit` is enabled, write the corresponding flag for parts and facades to [Metadata.extraInt]. - val extraFlags = context.backendExtension.generateMetadataExtraFlags(state.abiStability) - - val facadeClassName = context.multifileFacadeForPart[irClass.attributeOwnerId] - val metadata = irClass.metadata - val entry = irClass.fileParent.fileEntry - val kind = when { - facadeClassName != null -> KotlinClassHeader.Kind.MULTIFILE_CLASS_PART - metadata is MetadataSource.Class -> KotlinClassHeader.Kind.CLASS - metadata is MetadataSource.File -> KotlinClassHeader.Kind.FILE_FACADE - metadata is MetadataSource.Function -> KotlinClassHeader.Kind.SYNTHETIC_CLASS - entry is MultifileFacadeFileEntry -> KotlinClassHeader.Kind.MULTIFILE_CLASS - else -> KotlinClassHeader.Kind.SYNTHETIC_CLASS - } - writeKotlinMetadata(visitor, state, kind, extraFlags) { - if (metadata != null) { - metadataSerializer.serialize(metadata)?.let { (proto, stringTable) -> - DescriptorAsmUtil.writeAnnotationData(it, proto, stringTable) - } - } - - if (entry is MultifileFacadeFileEntry) { - val arv = it.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME) - for (partFile in entry.partFiles) { - val fileClass = partFile.declarations.singleOrNull { it.isFileClass } as IrClass? - if (fileClass != null) arv.visit(null, typeMapper.mapClass(fileClass).internalName) - } - arv.visitEnd() - } - - if (facadeClassName != null) { - it.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassName.internalName) - } - - if (irClass in context.classNameOverride) { - val isFileClass = kind == KotlinClassHeader.Kind.MULTIFILE_CLASS || - kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART || - kind == KotlinClassHeader.Kind.FILE_FACADE - assert(isFileClass) { "JvmPackageName is not supported for classes: ${irClass.render()}" } - it.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, irClass.fqNameWhenAvailable!!.parent().asString()) - } - } - } - - private fun IrFile.loadSourceFilesInfo(): List { - val entry = fileEntry - if (entry is MultifileFacadeFileEntry) { - return entry.partFiles.flatMap { it.loadSourceFilesInfo() } - } - return listOfNotNull(context.psiSourceManager.getFileEntry(this)?.let { File(it.name) }) - } - - companion object { - fun getOrCreate( - irClass: IrClass, - context: JvmBackendContext, - // The `parentFunction` is only set for classes nested inside of functions. This is usually safe, since there is no - // way to refer to (inline) members of such a class from outside of the function unless the function in question is - // itself declared as inline. In that case, the function will be compiled before we can refer to the nested class. - // - // The one exception to this rule are anonymous objects defined as members of a class. These are nested inside of the - // class initializer, but can be referred to from anywhere within the scope of the class. That's why we have to ensure - // that all references to classes inside of have a non-null `parentFunction`. - parentFunction: IrFunction? = irClass.parent.safeAs()?.takeIf { - it.origin == JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER - }, - ): ClassCodegen = - context.classCodegens.getOrPut(irClass) { ClassCodegen(irClass, context, parentFunction) }.also { - assert(parentFunction == null || it.parentFunction == parentFunction) { - "inconsistent parent function for ${irClass.render()}:\n" + - "New: ${parentFunction!!.render()}\n" + - "Old: ${it.parentFunction?.render()}" - } - } - - private fun JvmClassSignature.hasInvalidName() = - name.splitToSequence('/').any { identifier -> identifier.any { it in JvmSimpleNameBacktickChecker.INVALID_CHARS } } - } - - private fun generateField(field: IrField) { - val fieldType = typeMapper.mapType(field) - val fieldSignature = - if (field.origin == IrDeclarationOrigin.PROPERTY_DELEGATE) null - else context.methodSignatureMapper.mapFieldSignature(field) - val fieldName = field.name.asString() - val flags = field.computeFieldFlags(context, state.languageVersionSettings) - val fv = visitor.newField( - field.descriptorOrigin, flags, fieldName, fieldType.descriptor, - fieldSignature, (field.initializer?.expression as? IrConst<*>)?.value - ) - - jvmSignatureClashDetector.trackField(field, RawSignature(fieldName, fieldType.descriptor, MemberKind.FIELD)) - - if (field.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS_RESULT_FIELD) { - val skipNullabilityAnnotations = - flags and (Opcodes.ACC_SYNTHETIC or Opcodes.ACC_ENUM) != 0 || - field.origin == JvmLoweredDeclarationOrigin.FIELD_FOR_STATIC_CALLABLE_REFERENCE_INSTANCE - object : AnnotationCodegen(this@ClassCodegen, context, skipNullabilityAnnotations) { - override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor { - return fv.visitAnnotation(descr, visible) - } - - override fun visitTypeAnnotation(descr: String?, path: TypePath?, visible: Boolean): AnnotationVisitor { - return fv.visitTypeAnnotation(TypeReference.newTypeReference(TypeReference.FIELD).value, path, descr, visible) - } - }.genAnnotations(field, fieldType, field.type) - } - - (field.metadata as? MetadataSource.Property)?.let { - metadataSerializer.bindFieldMetadata(it, fieldType to fieldName) - } - - if (irClass.hasAnnotation(JVM_RECORD_ANNOTATION_FQ_NAME) && !field.isStatic) { - // TODO: Write annotations to the component - // visitor.newRecordComponent(fieldName, fieldType.descriptor, fieldSignature) - } - } - - private val generatedInlineMethods = mutableMapOf() - - fun generateMethodNode(method: IrFunction): SMAPAndMethodNode { - if (!method.isInline && !method.isSuspendCapturingCrossinline()) { - // Inline methods can be used multiple times by `IrSourceCompilerForInline`, suspend methods - // are used twice (`f` and `f$$forInline`) if they capture crossinline lambdas, and everything - // else is only generated by `generateMethod` below so does not need caching. - // TODO: inline lambdas are not marked `isInline`, and are generally used once, but may be needed - // multiple times if declared in a `finally` block - should they be cached? - return FunctionCodegen(method, this).generate() - } - val (node, smap) = generatedInlineMethods.getOrPut(method) { FunctionCodegen(method, this).generate() } - val copy = with(node) { MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions.toTypedArray()) } - node.instructions.resetLabels() - node.accept(copy) - return SMAPAndMethodNode(copy, smap) - } - - private fun generateMethod(method: IrFunction, classSMAP: SourceMapper, delegatedPropertyOptimizer: DelegatedPropertyOptimizer?) { - if (method.isFakeOverride) { - jvmSignatureClashDetector.trackFakeOverrideMethod(method) - return - } - - val (node, smap) = generateMethodNode(method) - if (delegatedPropertyOptimizer != null) { - delegatedPropertyOptimizer.transform(node) - if (method.name.asString() == "") { - delegatedPropertyOptimizer.transformClassInitializer(node) - } - } - node.preprocessSuspendMarkers( - method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE || method.isEffectivelyInlineOnly(), - method.origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE - ) - val mv = with(node) { visitor.newMethod(method.descriptorOrigin, access, name, desc, signature, exceptions.toTypedArray()) } - val smapCopier = SourceMapCopier(classSMAP, smap) - val smapCopyingVisitor = object : MethodVisitor(Opcodes.API_VERSION, mv) { - override fun visitLineNumber(line: Int, start: Label) = - super.visitLineNumber(smapCopier.mapLineNumber(line), start) - } - if (method.hasContinuation()) { - // Generate a state machine within this method. The continuation class for it should be generated - // lazily so that if tail call optimization kicks in, the unused class will not be written to the output. - val continuationClass = method.continuationClass() // null if `SuspendLambda.invokeSuspend` - `this` is continuation itself - val continuationClassCodegen = lazy { if (continuationClass != null) getOrCreate(continuationClass, context, method) else this } - node.acceptWithStateMachine(method, this, smapCopyingVisitor) { continuationClassCodegen.value.visitor } - if (continuationClass != null && (continuationClassCodegen.isInitialized() || method.isSuspendCapturingCrossinline())) { - continuationClassCodegen.value.generate() - } - } else { - node.accept(smapCopyingVisitor) - } - jvmSignatureClashDetector.trackMethod(method, RawSignature(node.name, node.desc, MemberKind.METHOD)) - - when (val metadata = method.metadata) { - is MetadataSource.Property -> { - assert(method.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_OR_TYPEALIAS_ANNOTATIONS) { - "MetadataSource.Property on IrFunction should only be used for synthetic \$annotations methods: ${method.render()}" - } - metadataSerializer.bindMethodMetadata(metadata, Method(node.name, node.desc)) - } - is MetadataSource.Function -> metadataSerializer.bindMethodMetadata(metadata, Method(node.name, node.desc)) - null -> Unit - else -> error("Incorrect metadata source $metadata for:\n${method.dump()}") - } - } - - private fun generateInnerAndOuterClasses() { - // JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information - // for each enclosing class and for each immediate member - parentClassCodegen?.innerClasses?.add(irClass) - for (codegen in generateSequence(this) { it.parentClassCodegen }.takeWhile { it.parentClassCodegen != null }) { - innerClasses.add(codegen.irClass) - } - - // JVMS7 (4.7.7): A class must have an EnclosingMethod attribute if and only if - // it is a local class or an anonymous class. - // - // The attribute contains the innermost class that encloses the declaration of - // the current class. If the current class is immediately enclosed by a method - // or constructor, the name and type of the function is recorded as well. - if (parentClassCodegen != null) { - // In case there's no primary constructor, it's unclear which constructor should be the enclosing one, so we select the first. - val enclosingFunction = if (irClass.attributeOwnerId in context.isEnclosedInConstructor) { - val containerClass = parentClassCodegen.irClass - containerClass.primaryConstructor - ?: containerClass.declarations.firstIsInstanceOrNull() - ?: error("Class in a non-static initializer found, but container has no constructors: ${containerClass.render()}") - } else parentFunction - if (enclosingFunction != null || irClass.isAnonymousObject) { - val method = enclosingFunction?.let(context.methodSignatureMapper::mapAsmMethod) - visitor.visitOuterClass(parentClassCodegen.type.internalName, method?.name, method?.descriptor) - } - } - - for (klass in innerClasses) { - val innerClass = typeMapper.classInternalName(klass) - val outerClass = - if (klass.attributeOwnerId in context.isEnclosedInConstructor) null - else klass.parent.safeAs()?.let(typeMapper::classInternalName) - val innerName = klass.name.takeUnless { it.isSpecial }?.asString() - visitor.visitInnerClass(innerClass, outerClass, innerName, klass.calculateInnerClassAccessFlags(context)) - } - } - - override fun addInnerClassInfoFromAnnotation(innerClass: IrClass) { - // It's necessary for proper recovering of classId by plain string JVM descriptor when loading annotations - // See FileBasedKotlinClass.convertAnnotationVisitor - generateSequence(innerClass) { it.parent as? IrDeclaration }.takeWhile { !it.isTopLevelDeclaration }.forEach { - if (it is IrClass) { - innerClasses.add(it) - } - } - } - - private val IrDeclaration.descriptorOrigin: JvmDeclarationOrigin - get() { - val psiElement = context.psiSourceManager.findPsiElement(this) - // For declarations inside lambdas, produce a descriptor which refers back to the original function. - // This is needed for plugins which check for lambdas inside of inline functions using the descriptor - // contained in JvmDeclarationOrigin. This matches the behavior of the JVM backend. - // TODO: this is really not very useful, as this does nothing for other anonymous objects. - val isLambda = irClass.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL || - irClass.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA - val descriptor = if (isLambda) - irClass.attributeOwnerId.safeAs()?.symbol?.owner?.toIrBasedDescriptor() ?: toIrBasedDescriptor() - else - toIrBasedDescriptor() - return if (origin == IrDeclarationOrigin.FILE_CLASS) - JvmDeclarationOrigin(JvmDeclarationOriginKind.PACKAGE_PART, psiElement, descriptor) - else - OtherOrigin(psiElement, descriptor) - } -} - -private val IrClass.flags: Int - get() = origin.flags or getVisibilityAccessFlagForClass() or - (if (isAnnotatedWithDeprecated) Opcodes.ACC_DEPRECATED else 0) or - (if (hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME)) Opcodes.ACC_SYNTHETIC else 0) or - when { - isAnnotationClass -> Opcodes.ACC_ANNOTATION or Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT - isInterface -> Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT - isEnumClass -> Opcodes.ACC_ENUM or Opcodes.ACC_SUPER or modality.flags - else -> Opcodes.ACC_SUPER or modality.flags - } - -private fun IrField.computeFieldFlags(context: JvmBackendContext, languageVersionSettings: LanguageVersionSettings): Int = - origin.flags or visibility.flags or - (if (isDeprecatedCallable(context) || - correspondingPropertySymbol?.owner?.isDeprecatedCallable(context) == true - ) Opcodes.ACC_DEPRECATED else 0) or - (if (isFinal) Opcodes.ACC_FINAL else 0) or - (if (isStatic) Opcodes.ACC_STATIC else 0) or - (if (hasAnnotation(VOLATILE_ANNOTATION_FQ_NAME)) Opcodes.ACC_VOLATILE else 0) or - (if (hasAnnotation(TRANSIENT_ANNOTATION_FQ_NAME)) Opcodes.ACC_TRANSIENT else 0) or - (if (hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) || - isPrivateCompanionFieldInInterface(languageVersionSettings) - ) Opcodes.ACC_SYNTHETIC else 0) - -private fun IrField.isPrivateCompanionFieldInInterface(languageVersionSettings: LanguageVersionSettings): Boolean = - origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE && - languageVersionSettings.supportsFeature(LanguageFeature.ProperVisibilityForCompanionObjectInstanceField) && - parentAsClass.isJvmInterface && - DescriptorVisibilities.isPrivate(parentAsClass.companionObject()!!.visibility) - -private val IrDeclarationOrigin.flags: Int - get() = (if (isSynthetic) Opcodes.ACC_SYNTHETIC else 0) or - (if (this == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY) Opcodes.ACC_ENUM else 0) - -private val Modality.flags: Int - get() = when (this) { - Modality.ABSTRACT, Modality.SEALED -> Opcodes.ACC_ABSTRACT - Modality.FINAL -> Opcodes.ACC_FINAL - Modality.OPEN -> 0 - else -> throw AssertionError("Unsupported modality $this") - } - -private val DescriptorVisibility.flags: Int - get() = DescriptorAsmUtil.getVisibilityAccessFlag(this) ?: throw AssertionError("Unsupported visibility $this")