org.jetbrains.kotlin.codegen.context.CodegenContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* 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.context;
import kotlin.annotations.jvm.ReadOnly;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.*;
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt;
import org.jetbrains.kotlin.resolve.sam.SamConstructorDescriptor;
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.storage.NullableLazyValue;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.org.objectweb.asm.Type;
import java.util.*;
import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getVisibilityAccessFlag;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInSamePackage;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isNonDefaultInterfaceMember;
import static org.jetbrains.kotlin.resolve.inline.InlineOnlyKt.isInlineOnlyPrivateInBytecode;
import static org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.isCallableMemberCompiledToJvmDefault;
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
@SuppressWarnings("rawtypes")
public abstract class CodegenContext {
private final T contextDescriptor;
private final OwnerKind contextKind;
private final CodegenContext parentContext;
private final ClassDescriptor thisDescriptor;
@Nullable public final MutableClosure closure;
private final LocalLookup enclosingLocalLookup;
private final NullableLazyValue outerExpression;
private Map childContexts;
private Map> accessors;
private Map propertyAccessorFactories;
private final Map accessorsForCompanionObjects =
new LinkedHashMap<>();
private static class AccessorKey {
public final DeclarationDescriptor descriptor;
public final ClassDescriptor superCallLabelTarget;
public final AccessorKind accessorKind;
public AccessorKey(
@NotNull DeclarationDescriptor descriptor,
@Nullable ClassDescriptor superCallLabelTarget,
@NotNull AccessorKind accessorKind
) {
this.descriptor = descriptor;
this.superCallLabelTarget = superCallLabelTarget;
this.accessorKind = accessorKind;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AccessorKey)) return false;
AccessorKey other = (AccessorKey) obj;
return descriptor.equals(other.descriptor) &&
accessorKind == other.accessorKind &&
Objects.equals(superCallLabelTarget, other.superCallLabelTarget);
}
@Override
public int hashCode() {
return 31 * descriptor.hashCode() +
accessorKind.hashCode() +
(superCallLabelTarget == null ? 0 : superCallLabelTarget.hashCode());
}
@Override
public String toString() {
return descriptor.toString();
}
}
private static class AccessorForPropertyDescriptorFactory {
private final @NotNull PropertyDescriptor property;
private final @NotNull DeclarationDescriptor containingDeclaration;
private final @Nullable ClassDescriptor superCallTarget;
private final @NotNull String nameSuffix;
private final @NotNull AccessorKind accessorKind;
private AccessorForPropertyDescriptor withSyntheticGetterAndSetter = null;
private AccessorForPropertyDescriptor withSyntheticGetter = null;
private AccessorForPropertyDescriptor withSyntheticSetter = null;
public AccessorForPropertyDescriptorFactory(
@NotNull PropertyDescriptor property,
@NotNull DeclarationDescriptor containingDeclaration,
@Nullable ClassDescriptor superCallTarget,
@NotNull String nameSuffix,
@NotNull AccessorKind accessorKind
) {
this.property = property;
this.containingDeclaration = containingDeclaration;
this.superCallTarget = superCallTarget;
this.nameSuffix = nameSuffix;
this.accessorKind = accessorKind;
}
@SuppressWarnings("ConstantConditions")
public PropertyDescriptor getOrCreateAccessorIfNeeded(boolean getterAccessorRequired, boolean setterAccessorRequired) {
if (getterAccessorRequired && setterAccessorRequired) {
return getOrCreateAccessorWithSyntheticGetterAndSetter();
}
else if (getterAccessorRequired && !setterAccessorRequired) {
if (withSyntheticGetter == null) {
withSyntheticGetter = new AccessorForPropertyDescriptor(
property, containingDeclaration, superCallTarget, nameSuffix,
true, false, accessorKind);
}
return withSyntheticGetter;
}
else if (!getterAccessorRequired && setterAccessorRequired) {
if (withSyntheticSetter == null) {
withSyntheticSetter = new AccessorForPropertyDescriptor(
property, containingDeclaration, superCallTarget, nameSuffix,
false, true, accessorKind);
}
return withSyntheticSetter;
}
else {
return property;
}
}
@NotNull
public AccessorForPropertyDescriptor getOrCreateAccessorWithSyntheticGetterAndSetter() {
if (withSyntheticGetterAndSetter == null) {
withSyntheticGetterAndSetter = new AccessorForPropertyDescriptor(
property, containingDeclaration, superCallTarget, nameSuffix,
true, true, accessorKind);
}
return withSyntheticGetterAndSetter;
}
}
public CodegenContext(
@NotNull T contextDescriptor,
@NotNull OwnerKind contextKind,
@Nullable CodegenContext parentContext,
@Nullable MutableClosure closure,
@Nullable ClassDescriptor thisDescriptor,
@Nullable LocalLookup localLookup
) {
this.contextDescriptor = contextDescriptor;
this.contextKind = contextKind;
this.parentContext = parentContext;
this.closure = closure;
this.thisDescriptor = thisDescriptor;
this.enclosingLocalLookup = localLookup;
this.outerExpression = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue(this::computeOuterExpression);
if (parentContext != null) {
parentContext.addChild(this);
}
}
@NotNull
public GenerationState getState() {
return parentContext.getState();
}
@NotNull
public final ClassDescriptor getThisDescriptor() {
if (thisDescriptor == null) {
throw new UnsupportedOperationException("Context doesn't have a \"this\": " + this);
}
return thisDescriptor;
}
public final boolean hasThisDescriptor() {
return thisDescriptor != null;
}
@NotNull
@SuppressWarnings("unchecked")
public CodegenContext extends ClassOrPackageFragmentDescriptor> getClassOrPackageParentContext() {
CodegenContext> context = this;
while (true) {
if (context.getContextDescriptor() instanceof ClassOrPackageFragmentDescriptor) {
return (CodegenContext) context;
}
context = context.getParentContext();
assert context != null : "Context which is not top-level has no parent: " + this;
}
}
/**
* This method returns not null only if context descriptor corresponds to method or function which has receiver
*/
@Nullable
public final CallableDescriptor getCallableDescriptorWithReceiver() {
if (contextDescriptor instanceof CallableDescriptor) {
CallableDescriptor callableDescriptor = (CallableDescriptor) getContextDescriptor();
return callableDescriptor.getExtensionReceiverParameter() != null ? callableDescriptor : null;
}
return null;
}
public StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter) {
return getOuterExpression(prefix, ignoreNoOuter, true);
}
private StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter, boolean captureThis) {
if (outerExpression.invoke() == null) {
if (!ignoreNoOuter) {
throw new UnsupportedOperationException("Don't know how to generate outer expression: " + this);
}
return null;
}
if (captureThis) {
if (closure == null) {
throw new IllegalStateException("Can't capture this for context without closure: " + this);
}
closure.setNeedsCaptureOuterClass();
}
return StackValue.changeReceiverForFieldAndSharedVar(outerExpression.invoke(), prefix);
}
@NotNull
public T getContextDescriptor() {
return contextDescriptor;
}
@NotNull
public OwnerKind getContextKind() {
return contextKind;
}
@NotNull
public PackageContext intoPackagePart(@NotNull PackageFragmentDescriptor descriptor, Type packagePartType, @Nullable KtFile sourceFile) {
return new PackageContext(descriptor, this, packagePartType, sourceFile);
}
@NotNull
public MultifileClassPartContext intoMultifileClassPart(
@NotNull PackageFragmentDescriptor descriptor,
@NotNull Type multifileClassType,
@NotNull Type filePartType,
@NotNull KtFile sourceFile
) {
return new MultifileClassPartContext(descriptor, this, multifileClassType, filePartType, sourceFile);
}
@NotNull
public FieldOwnerContext intoMultifileClass(
@NotNull PackageFragmentDescriptor descriptor,
@NotNull Type multifileClassType,
@NotNull Type filePartType
) {
return new MultifileClassFacadeContext(descriptor, this, multifileClassType, filePartType);
}
public ClassContext intoDefaultImplsClass(ClassDescriptor descriptor, ClassContext interfaceContext, GenerationState state) {
return new DefaultImplsClassContext(state.getTypeMapper(), descriptor, OwnerKind.DEFAULT_IMPLS, this, null, interfaceContext);
}
@NotNull
public ClassContext intoClass(@NotNull ClassDescriptor descriptor, @NotNull OwnerKind kind, @NotNull GenerationState state) {
if (shouldAddChild(descriptor)) {
CodegenContext savedContext = this.findChildContext(descriptor);
if (savedContext != null) {
assert savedContext.getContextKind() == kind : "Kinds should be same, but: " +
savedContext.getContextKind() + "!= " + kind;
return (ClassContext) savedContext;
}
}
ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
if (descriptor.getCompanionObjectDescriptor() != null) {
//We need to create companion object context ahead of time
// because otherwise we can't generate synthetic accessor for private members in companion object
classContext.intoClass(descriptor.getCompanionObjectDescriptor(), OwnerKind.IMPLEMENTATION, state);
}
return classContext;
}
@NotNull
public ClassContext intoAnonymousClass(@NotNull ClassDescriptor descriptor, @NotNull ExpressionCodegen codegen, @NotNull OwnerKind ownerKind) {
return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen);
}
@NotNull
public MethodContext intoFunction(FunctionDescriptor descriptor, boolean isDefaultFunctionContext) {
return new MethodContext(descriptor, getContextKind(), this, null, isDefaultFunctionContext);
}
@NotNull
public MethodContext intoFunction(FunctionDescriptor descriptor) {
return intoFunction(descriptor, false);
}
@NotNull
public MethodContext intoInlinedLambda(FunctionDescriptor descriptor, boolean isCrossInline, boolean isPropertyReference) {
return new InlineLambdaContext(descriptor, getContextKind(), this, null, isCrossInline, isPropertyReference);
}
@NotNull
public ConstructorContext intoConstructor(@NotNull ConstructorDescriptor descriptor, @NotNull KotlinTypeMapper typeMapper) {
return new ConstructorContext(descriptor, getContextKind(), this, closure, typeMapper);
}
@NotNull
public ScriptContext intoScript(
@NotNull ScriptDescriptor script,
@NotNull List earlierScripts,
@NotNull ClassDescriptor classDescriptor,
@NotNull KotlinTypeMapper typeMapper
) {
return new ScriptContext(typeMapper, script, earlierScripts, classDescriptor, this);
}
@NotNull
public ClosureContext intoClosure(
@NotNull FunctionDescriptor funDescriptor,
@NotNull LocalLookup localLookup,
@NotNull KotlinTypeMapper typeMapper
) {
return new ClosureContext(typeMapper, funDescriptor, this, localLookup);
}
@NotNull
public ClosureContext intoCoroutineClosure(
// copy of lambda descriptor that has an additional value parameter Continuation
@NotNull FunctionDescriptor jvmViewOfSuspendLambda,
// original coroutine lambda descriptor
@NotNull FunctionDescriptor originalSuspendLambdaDescriptor,
@NotNull LocalLookup localLookup,
@NotNull KotlinTypeMapper typeMapper
) {
return new ClosureContext(typeMapper, jvmViewOfSuspendLambda, this, localLookup, originalSuspendLambdaDescriptor);
}
public ClassContext intoWrapperForErasedInlineClass(ClassDescriptor descriptor, GenerationState state) {
return new ClassContext(state.getTypeMapper(), descriptor, OwnerKind.ERASED_INLINE_CLASS, this, null);
}
@Nullable
public CodegenContext getParentContext() {
return parentContext;
}
public boolean isContextWithUninitializedThis() {
return false;
}
@Nullable
public CodegenContext getEnclosingClassContext() {
CodegenContext cur = getEnclosingThisContext();
while (cur != null) {
DeclarationDescriptor curDescriptor = cur.getContextDescriptor();
if (curDescriptor instanceof ClassDescriptor) {
return cur;
}
cur = cur.getParentContext();
}
return null;
}
@Nullable
public CodegenContext getEnclosingThisContext() {
CodegenContext cur = getParentContext();
while (cur != null && cur.isContextWithUninitializedThis()) {
CodegenContext parent = cur.getParentContext();
assert parent != null : "Context " + cur + " should have a parent";
cur = parent.getParentContext();
}
return cur;
}
@Nullable
public ClassDescriptor getEnclosingClass() {
// TODO store enclosing context class in the context itself
CodegenContext enclosingClassContext = getEnclosingClassContext();
if (enclosingClassContext == null) return null;
return (ClassDescriptor) enclosingClassContext.getContextDescriptor();
}
@Nullable
public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) {
CodegenContext c = this;
while (c != null) {
if (!c.isShadowedByParentContext() && c.getContextDescriptor() == descriptor) break;
c = c.getParentContext();
}
return c;
}
private boolean isShadowedByParentContext() {
return getContextKind() == OwnerKind.ERASED_INLINE_CLASS;
}
@NotNull
private PropertyDescriptor getPropertyAccessor(
@NotNull PropertyDescriptor propertyDescriptor,
@Nullable ClassDescriptor superCallTarget,
boolean getterAccessorRequired,
boolean setterAccessorRequired
) {
return getAccessor(propertyDescriptor, AccessorKind.NORMAL, null, superCallTarget, getterAccessorRequired, setterAccessorRequired);
}
@SuppressWarnings("unchecked")
public D getAccessorForJvmDefaultCompatibility(@NotNull D descriptor) {
if (descriptor instanceof PropertyAccessorDescriptor) {
PropertyDescriptor propertyAccessor = getAccessor(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty(),
AccessorKind.JVM_DEFAULT_COMPATIBILITY, null, null,
descriptor instanceof PropertyGetterDescriptor,
descriptor instanceof PropertySetterDescriptor);
return descriptor instanceof PropertyGetterDescriptor ? (D) propertyAccessor.getGetter() : (D) propertyAccessor.getSetter();
}
return getAccessor(descriptor, AccessorKind.JVM_DEFAULT_COMPATIBILITY, null, null);
}
@NotNull
private D getAccessor(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
return getAccessor(descriptor, AccessorKind.NORMAL, null, superCallTarget);
}
@SuppressWarnings("unchecked")
@NotNull
public D getAccessorForSuperCallIfNeeded(
@NotNull D descriptor,
@Nullable ClassDescriptor superCallTarget,
@NotNull GenerationState state) {
if (superCallTarget != null && !isNonDefaultInterfaceMember(descriptor, state.getJvmDefaultMode())) {
CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext();
CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget);
assert c != null : "Couldn't find a context for a super-call: " + descriptor;
if (c != afterInline.getParentContext()) {
return (D) c.getAccessor(descriptor, superCallTarget);
}
}
return descriptor;
}
@NotNull
public D getAccessor(
@NotNull D possiblySubstitutedDescriptor,
@NotNull AccessorKind accessorKind,
@Nullable KotlinType delegateType,
@Nullable ClassDescriptor superCallTarget
) {
// TODO this corresponds to default behavior for properties before fixing KT-9717. Is it Ok in general case?
// Does not matter for other descriptor kinds.
return getAccessor(possiblySubstitutedDescriptor, accessorKind, delegateType, superCallTarget,
/* getterAccessorRequired */ true,
/* setterAccessorRequired */ true);
}
@SuppressWarnings("unchecked")
@NotNull
private D getAccessor(
@NotNull D possiblySubstitutedDescriptor,
@NotNull AccessorKind accessorKind,
@Nullable KotlinType delegateType,
@Nullable ClassDescriptor superCallTarget,
boolean getterAccessorRequired,
boolean setterAccessorRequired
) {
if (accessors == null) {
accessors = new LinkedHashMap<>();
}
if (propertyAccessorFactories == null) {
propertyAccessorFactories = new LinkedHashMap<>();
}
D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
AccessorKey key = new AccessorKey(descriptor, superCallTarget, accessorKind);
// NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key);
if (propertyAccessorFactory != null) {
return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
}
AccessorForCallableDescriptor> accessor = accessors.get(key);
if (accessor != null) {
assert accessorKind == AccessorKind.NORMAL ||
accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
return (D) accessor;
}
String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
if (descriptor instanceof SimpleFunctionDescriptor) {
accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix, accessorKind);
}
else if (descriptor instanceof ClassConstructorDescriptor) {
accessor = new AccessorForConstructorDescriptor((ClassConstructorDescriptor) descriptor, contextDescriptor, superCallTarget, accessorKind);
}
else if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (accessorKind == AccessorKind.NORMAL || accessorKind == AccessorKind.JVM_DEFAULT_COMPATIBILITY) {
AccessorForPropertyDescriptorFactory factory =
new AccessorForPropertyDescriptorFactory(propertyDescriptor, contextDescriptor, superCallTarget, nameSuffix, accessorKind);
propertyAccessorFactories.put(key, factory);
// Record worst case accessor for accessor methods generation.
accessors.put(key, factory.getOrCreateAccessorWithSyntheticGetterAndSetter());
return (D) factory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
}
accessor = new AccessorForPropertyBackingField(
propertyDescriptor, contextDescriptor, delegateType,
accessorKind == AccessorKind.IN_CLASS_COMPANION ? null : propertyDescriptor.getExtensionReceiverParameter(),
accessorKind == AccessorKind.IN_CLASS_COMPANION ? null : propertyDescriptor.getDispatchReceiverParameter(),
nameSuffix, accessorKind
);
}
else {
throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor +
" in context " + this);
}
accessors.put(key, accessor);
return (D) accessor;
}
@Nullable
protected StackValue.Field computeOuterExpression() {
return null;
}
public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
StackValue myOuter = null;
if (closure != null) {
EnclosedValueDescriptor capturedVariable = closure.getCaptureVariables().get(d);
if (capturedVariable != null) {
return StackValue.changeReceiverForFieldAndSharedVar(capturedVariable.getInnerValue(), result);
}
for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
if (aCase.isCase(d)) {
Type classType = state.getTypeMapper().mapType(getThisDescriptor());
StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
if (innerValue == null) {
break;
}
else {
return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
}
}
}
myOuter = getOuterExpression(result, ignoreNoOuter, false);
result = myOuter;
}
StackValue resultValue;
if (myOuter != null && getEnclosingClass() == d) {
resultValue = result;
}
else {
CodegenContext enclosingClassContext = getEnclosingThisContext();
resultValue = enclosingClassContext != null ? enclosingClassContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
}
if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
closure.setNeedsCaptureOuterClass();
}
return resultValue;
}
@NotNull
@ReadOnly
public Collection extends AccessorForCallableDescriptor>> getAccessors() {
return accessors == null ? Collections.>emptySet() : accessors.values();
}
@SuppressWarnings("unchecked")
@NotNull
public D accessibleDescriptor(
@NotNull D descriptor,
@Nullable ClassDescriptor superCallTarget
) {
CodegenContext properContext = getFirstCrossInlineOrNonInlineContext();
DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
boolean isInliningContext = properContext.isInlineMethodContext();
boolean sameJvmDefault = JvmAnnotationUtilKt.isCompiledToJvmDefault(descriptor, getState().getJvmDefaultMode()) ==
isCallableMemberCompiledToJvmDefault(properContext.contextDescriptor, getState().getJvmDefaultMode()) ||
properContext.contextDescriptor instanceof AccessorForCallableDescriptor;
if (!isInliningContext && (
!properContext.hasThisDescriptor() ||
((enclosing == properContext.getThisDescriptor()) && sameJvmDefault) ||
((enclosing == properContext.getClassOrPackageParentContext().getContextDescriptor()) && sameJvmDefault))) {
return descriptor;
}
return (D) properContext.accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
}
@SuppressWarnings("unchecked")
@NotNull
private D accessibleDescriptorIfNeeded(
@NotNull D descriptor,
@Nullable ClassDescriptor superCallTarget,
boolean withinInliningContext
) {
CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
CodegenContext descriptorContext = findParentContextWithDescriptor(enclosed);
if (descriptorContext == null && DescriptorUtils.isCompanionObject(enclosed)) {
CodegenContext classContext = findParentContextWithDescriptor(enclosed.getContainingDeclaration());
if (classContext instanceof ClassContext) {
descriptorContext = ((ClassContext) classContext).getCompanionObjectContext();
}
}
if (descriptorContext == null &&
JavaDescriptorVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() &&
(!(descriptor.getOriginal() instanceof SamConstructorDescriptor))) {
//seems we need static receiver in resolved call
descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
superCallTarget = (ClassDescriptor) enclosed;
}
if (descriptorContext == null && withinInliningContext && superCallTarget != null) {
//generate super calls within inline function through synthetic accessors
descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
}
if (descriptorContext == null && descriptor instanceof ClassConstructorDescriptor) {
ClassDescriptor classDescriptor = ((ClassConstructorDescriptor) descriptor).getContainingDeclaration();
if (DescriptorUtils.isSealedClass(classDescriptor)) {
CodegenContext parentContextForClass = findParentContextWithDescriptor(classDescriptor.getContainingDeclaration());
if (parentContextForClass != null) {
//generate super constructor calls for top-level sealed classes from top level child
descriptorContext = parentContextForClass.findChildContext(classDescriptor);
}
}
}
if (descriptorContext == null) {
return descriptor;
}
if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
int propertyAccessFlag = getVisibilityAccessFlag(descriptor);
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
int getterAccessFlag = getter == null ? propertyAccessFlag
: propertyAccessFlag | getVisibilityAccessFlag(getter);
boolean getterAccessorRequired = isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext,
withinInliningContext, superCallTarget != null);
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
int setterAccessFlag = propertyAccessFlag;
if (setter != null && setter.getVisibility().normalize() != DescriptorVisibilities.INVISIBLE_FAKE) {
setterAccessFlag = propertyAccessFlag | getVisibilityAccessFlag(setter);
}
boolean setterAccessorRequired = isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext,
withinInliningContext, superCallTarget != null);
if (!getterAccessorRequired && !setterAccessorRequired) {
return descriptor;
}
return (D) descriptorContext.getPropertyAccessor(propertyDescriptor, superCallTarget, getterAccessorRequired, setterAccessorRequired);
}
else {
int flag = getVisibilityAccessFlag(unwrappedDescriptor);
if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext, withinInliningContext, superCallTarget != null)) {
return descriptor;
}
return (D) descriptorContext.getAccessor(descriptor, superCallTarget);
}
}
private static boolean isAccessorRequired(
int accessFlag,
@NotNull CallableMemberDescriptor unwrappedDescriptor,
@NotNull CodegenContext descriptorContext,
boolean withinInline,
boolean isSuperCall
) {
if (isInlineOnlyPrivateInBytecode(unwrappedDescriptor)) return false;
return isSuperCall && withinInline ||
(accessFlag & ACC_PRIVATE) != 0 ||
((accessFlag & ACC_PROTECTED) != 0 &&
(withinInline || !isInSamePackage(unwrappedDescriptor, descriptorContext.getContextDescriptor())));
}
private void addChild(@NotNull CodegenContext child) {
if (shouldAddChild(child.contextDescriptor)) {
if (childContexts == null) {
childContexts = new HashMap<>();
}
DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
childContexts.put(childContextDescriptor, child);
}
}
private static boolean shouldAddChild(@NotNull DeclarationDescriptor childContextDescriptor) {
return DescriptorUtils.isCompanionObject(childContextDescriptor) || DescriptorUtils.isSealedClass(childContextDescriptor);
}
@Nullable
protected CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
return childContexts == null ? null : childContexts.get(child);
}
private static boolean isStaticField(@NotNull StackValue value) {
return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
}
public boolean isInlineMethodContext() {
return false;
}
@NotNull
public CodegenContext getFirstCrossInlineOrNonInlineContext() {
return this;
}
@Nullable
public LocalLookup getEnclosingLocalLookup() {
return enclosingLocalLookup;
}
@SuppressWarnings("UnusedReturnValue")
@NotNull
public AccessorForCompanionObjectInstanceFieldDescriptor getOrCreateAccessorForCompanionObject(
@NotNull ClassDescriptor companionObjectDescriptor
) {
return accessorsForCompanionObjects.computeIfAbsent(
companionObjectDescriptor,
it -> new AccessorForCompanionObjectInstanceFieldDescriptor(
it,
Name.identifier(JvmCodegenUtil.getCompanionObjectAccessorName(it))
)
);
}
@NotNull
public Collection getRequiredAccessorsForCompanionObjects() {
return accessorsForCompanionObjects.values();
}
}