001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.codegen.context;
018    
019    import kotlin.jvm.functions.Function0;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.annotations.ReadOnly;
023    import org.jetbrains.kotlin.codegen.*;
024    import org.jetbrains.kotlin.codegen.binding.MutableClosure;
025    import org.jetbrains.kotlin.codegen.state.GenerationState;
026    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
027    import org.jetbrains.kotlin.descriptors.*;
028    import org.jetbrains.kotlin.load.java.JavaVisibilities;
029    import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
030    import org.jetbrains.kotlin.psi.KtFile;
031    import org.jetbrains.kotlin.resolve.DescriptorUtils;
032    import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
033    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
034    import org.jetbrains.kotlin.storage.NullableLazyValue;
035    import org.jetbrains.kotlin.types.KotlinType;
036    import org.jetbrains.org.objectweb.asm.Type;
037    
038    import java.util.*;
039    
040    import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityAccessFlag;
041    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
042    import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
043    import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
044    
045    public abstract class CodegenContext<T extends DeclarationDescriptor> {
046        private final T contextDescriptor;
047        private final OwnerKind contextKind;
048        private final CodegenContext parentContext;
049        private final ClassDescriptor thisDescriptor;
050        public final MutableClosure closure;
051        private final LocalLookup enclosingLocalLookup;
052        private final NullableLazyValue<StackValue.Field> outerExpression;
053    
054        private Map<DeclarationDescriptor, CodegenContext> childContexts;
055        private Map<AccessorKey, AccessorForCallableDescriptor<?>> accessors;
056        private Map<AccessorKey, AccessorForPropertyDescriptorFactory> propertyAccessorFactories;
057    
058        private static class AccessorKey {
059            public final DeclarationDescriptor descriptor;
060            public final ClassDescriptor superCallLabelTarget;
061    
062            public AccessorKey(
063                    @NotNull DeclarationDescriptor descriptor,
064                    @Nullable ClassDescriptor superCallLabelTarget
065            ) {
066                this.descriptor = descriptor;
067                this.superCallLabelTarget = superCallLabelTarget;
068            }
069    
070            @Override
071            public boolean equals(Object obj) {
072                if (!(obj instanceof AccessorKey)) return false;
073                AccessorKey other = (AccessorKey) obj;
074                return descriptor.equals(other.descriptor) &&
075                       (superCallLabelTarget == null ? other.superCallLabelTarget == null
076                                                     : superCallLabelTarget.equals(other.superCallLabelTarget));
077            }
078    
079            @Override
080            public int hashCode() {
081                return 31 * descriptor.hashCode() + (superCallLabelTarget == null ? 0 : superCallLabelTarget.hashCode());
082            }
083    
084            @Override
085            public String toString() {
086                return descriptor.toString();
087            }
088        }
089    
090        private static class AccessorForPropertyDescriptorFactory {
091            private final @NotNull PropertyDescriptor property;
092            private final @NotNull DeclarationDescriptor containingDeclaration;
093            private final @Nullable ClassDescriptor superCallTarget;
094            private final @NotNull String nameSuffix;
095    
096            private AccessorForPropertyDescriptor withSyntheticGetterAndSetter = null;
097            private AccessorForPropertyDescriptor withSyntheticGetter = null;
098            private AccessorForPropertyDescriptor withSyntheticSetter = null;
099    
100            public AccessorForPropertyDescriptorFactory(
101                    @NotNull PropertyDescriptor property,
102                    @NotNull DeclarationDescriptor containingDeclaration,
103                    @Nullable ClassDescriptor superCallTarget,
104                    @NotNull String nameSuffix
105            ) {
106                this.property = property;
107                this.containingDeclaration = containingDeclaration;
108                this.superCallTarget = superCallTarget;
109                this.nameSuffix = nameSuffix;
110            }
111    
112            @SuppressWarnings("ConstantConditions")
113            public PropertyDescriptor getOrCreateAccessorIfNeeded(boolean getterAccessorRequired, boolean setterAccessorRequired) {
114                if (getterAccessorRequired && setterAccessorRequired) {
115                    return getOrCreateAccessorWithSyntheticGetterAndSetter();
116                }
117                else if (getterAccessorRequired && !setterAccessorRequired) {
118                    if (withSyntheticGetter == null) {
119                        withSyntheticGetter = new AccessorForPropertyDescriptor(
120                                property, containingDeclaration, superCallTarget, nameSuffix,
121                                true, false);
122                    }
123                    return withSyntheticGetter;
124                }
125                else if (!getterAccessorRequired && setterAccessorRequired) {
126                    if (withSyntheticSetter == null) {
127                        withSyntheticSetter = new AccessorForPropertyDescriptor(
128                                property, containingDeclaration, superCallTarget, nameSuffix,
129                                false, true);
130                    }
131                    return withSyntheticSetter;
132                }
133                else {
134                    return property;
135                }
136            }
137    
138            @NotNull
139            public AccessorForPropertyDescriptor getOrCreateAccessorWithSyntheticGetterAndSetter() {
140                if (withSyntheticGetterAndSetter == null) {
141                    withSyntheticGetterAndSetter = new AccessorForPropertyDescriptor(
142                            property, containingDeclaration, superCallTarget, nameSuffix,
143                            true, true);
144                }
145                return withSyntheticGetterAndSetter;
146            }
147        }
148    
149        public CodegenContext(
150                @NotNull T contextDescriptor,
151                @NotNull OwnerKind contextKind,
152                @Nullable CodegenContext parentContext,
153                @Nullable MutableClosure closure,
154                @Nullable ClassDescriptor thisDescriptor,
155                @Nullable LocalLookup localLookup
156        ) {
157            this.contextDescriptor = contextDescriptor;
158            this.contextKind = contextKind;
159            this.parentContext = parentContext;
160            this.closure = closure;
161            this.thisDescriptor = thisDescriptor;
162            this.enclosingLocalLookup = localLookup;
163            this.outerExpression = LockBasedStorageManager.NO_LOCKS.createNullableLazyValue(new Function0<StackValue.Field>() {
164                @Override
165                public StackValue.Field invoke() {
166                    return computeOuterExpression();
167                }
168            });
169    
170            if (parentContext != null) {
171                parentContext.addChild(this);
172            }
173        }
174    
175        @NotNull
176        public GenerationState getState() {
177            return parentContext.getState();
178        }
179    
180        @NotNull
181        public final ClassDescriptor getThisDescriptor() {
182            if (thisDescriptor == null) {
183                throw new UnsupportedOperationException("Context doesn't have a \"this\": " + this);
184            }
185            return thisDescriptor;
186        }
187    
188        public final boolean hasThisDescriptor() {
189            return thisDescriptor != null;
190        }
191    
192        @NotNull
193        @SuppressWarnings("unchecked")
194        public CodegenContext<? extends ClassOrPackageFragmentDescriptor> getClassOrPackageParentContext() {
195            CodegenContext<?> context = this;
196            while (true) {
197                if (context.getContextDescriptor() instanceof ClassOrPackageFragmentDescriptor) {
198                    return (CodegenContext) context;
199                }
200                context = context.getParentContext();
201                assert context != null : "Context which is not top-level has no parent: " + this;
202            }
203        }
204    
205        /**
206         * This method returns not null only if context descriptor corresponds to method or function which has receiver
207         */
208        @Nullable
209        public final CallableDescriptor getCallableDescriptorWithReceiver() {
210            if (contextDescriptor instanceof CallableDescriptor) {
211                CallableDescriptor callableDescriptor = (CallableDescriptor) getContextDescriptor();
212                return callableDescriptor.getExtensionReceiverParameter() != null ? callableDescriptor : null;
213            }
214            return null;
215        }
216    
217        public StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter) {
218            return getOuterExpression(prefix, ignoreNoOuter, true);
219        }
220    
221        private StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter, boolean captureThis) {
222            if (outerExpression.invoke() == null) {
223                if (!ignoreNoOuter) {
224                    throw new UnsupportedOperationException("Don't know how to generate outer expression for " + getContextDescriptor());
225                }
226                return null;
227            }
228            if (captureThis) {
229                if (closure == null) {
230                    throw new IllegalStateException("Can't capture this for context without closure: " + getContextDescriptor());
231                }
232                closure.setCaptureThis();
233            }
234            return StackValue.changeReceiverForFieldAndSharedVar(outerExpression.invoke(), prefix);
235        }
236    
237        @NotNull
238        public T getContextDescriptor() {
239            return contextDescriptor;
240        }
241    
242        @NotNull
243        public OwnerKind getContextKind() {
244            return contextKind;
245        }
246    
247        @NotNull
248        public PackageContext intoPackagePart(@NotNull PackageFragmentDescriptor descriptor, Type packagePartType, @Nullable KtFile sourceFile) {
249            return new PackageContext(descriptor, this, packagePartType, sourceFile);
250        }
251    
252        @NotNull
253        public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClassPart(
254                @NotNull PackageFragmentDescriptor descriptor,
255                @NotNull Type multifileClassType,
256                @NotNull Type filePartType,
257                @NotNull KtFile sourceFile
258        ) {
259            return new MultifileClassPartContext(descriptor, this, multifileClassType, filePartType, sourceFile);
260        }
261    
262        @NotNull
263        public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClass(
264                @NotNull PackageFragmentDescriptor descriptor,
265                @NotNull Type multifileClassType,
266                @NotNull Type filePartType
267        ) {
268            return new MultifileClassFacadeContext(descriptor, this, multifileClassType, filePartType);
269        }
270    
271        public ClassContext intoDefaultImplsClass(ClassDescriptor descriptor, ClassContext interfaceContext, GenerationState state) {
272            return new DefaultImplsClassContext(state.getTypeMapper(), descriptor, OwnerKind.DEFAULT_IMPLS, this, null, interfaceContext);
273        }
274    
275        @NotNull
276        public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
277            if (descriptor.isCompanionObject()) {
278                CodegenContext companionContext = this.findChildContext(descriptor);
279                if (companionContext != null) {
280                    assert companionContext.getContextKind() == kind : "Kinds should be same, but: " +
281                                                                       companionContext.getContextKind() + "!= " + kind;
282                    return (ClassContext) companionContext;
283                }
284            }
285            ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
286    
287            if (descriptor.getCompanionObjectDescriptor() != null) {
288                //We need to create companion object context ahead of time
289                // because otherwise we can't generate synthetic accessor for private members in companion object
290                classContext.intoClass(descriptor.getCompanionObjectDescriptor(), OwnerKind.IMPLEMENTATION, state);
291            }
292            return classContext;
293        }
294    
295        @NotNull
296        public ClassContext intoAnonymousClass(@NotNull ClassDescriptor descriptor, @NotNull ExpressionCodegen codegen, @NotNull OwnerKind ownerKind) {
297            return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen);
298        }
299    
300        @NotNull
301        public MethodContext intoFunction(FunctionDescriptor descriptor) {
302            return new MethodContext(descriptor, getContextKind(), this, null);
303        }
304    
305        @NotNull
306        public MethodContext intoInlinedLambda(FunctionDescriptor descriptor, boolean isCrossInline) {
307            return new InlineLambdaContext(descriptor, getContextKind(), this, null, isCrossInline);
308        }
309    
310        @NotNull
311        public ConstructorContext intoConstructor(@NotNull ConstructorDescriptor descriptor) {
312            return new ConstructorContext(descriptor, getContextKind(), this, closure);
313        }
314    
315        @NotNull
316        public ScriptContext intoScript(
317                @NotNull ScriptDescriptor script,
318                @NotNull List<ScriptDescriptor> earlierScripts,
319                @NotNull ClassDescriptor classDescriptor,
320                @NotNull JetTypeMapper typeMapper
321        ) {
322            return new ScriptContext(typeMapper, script, earlierScripts, classDescriptor, this);
323        }
324    
325        @NotNull
326        public ClosureContext intoClosure(
327                @NotNull FunctionDescriptor funDescriptor,
328                @NotNull LocalLookup localLookup,
329                @NotNull JetTypeMapper typeMapper
330        ) {
331            return new ClosureContext(typeMapper, funDescriptor, this, localLookup);
332        }
333    
334        @Nullable
335        public CodegenContext getParentContext() {
336            return parentContext;
337        }
338    
339        public ClassDescriptor getEnclosingClass() {
340            CodegenContext cur = getParentContext();
341            while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) {
342                cur = cur.getParentContext();
343            }
344    
345            return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor();
346        }
347    
348        @Nullable
349        public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) {
350            CodegenContext c = this;
351            while (c != null) {
352                if (c.getContextDescriptor() == descriptor) break;
353                c = c.getParentContext();
354            }
355            return c;
356        }
357    
358        @NotNull
359        private PropertyDescriptor getPropertyAccessor(
360                @NotNull PropertyDescriptor propertyDescriptor,
361                @Nullable ClassDescriptor superCallTarget,
362                boolean getterAccessorRequired,
363                boolean setterAccessorRequired
364        ) {
365            return getAccessor(propertyDescriptor, FieldAccessorKind.NORMAL, null, superCallTarget, getterAccessorRequired, setterAccessorRequired);
366        }
367    
368        @NotNull
369        private <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
370            return getAccessor(descriptor, FieldAccessorKind.NORMAL, null, superCallTarget);
371        }
372    
373        @SuppressWarnings("unchecked")
374        @NotNull
375        public <D extends CallableMemberDescriptor> D getAccessorForSuperCallIfNeeded(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
376            if (superCallTarget != null && !isJvmInterface(descriptor.getContainingDeclaration())) {
377                CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext();
378                CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget);
379                assert c != null : "Couldn't find a context for a super-call: " + descriptor;
380                if (c != afterInline.getParentContext()) {
381                    return (D) c.getAccessor(descriptor, superCallTarget);
382                }
383            }
384            return descriptor;
385        }
386    
387        @NotNull
388        public <D extends CallableMemberDescriptor> D getAccessor(
389                @NotNull D possiblySubstitutedDescriptor,
390                @NotNull FieldAccessorKind accessorKind,
391                @Nullable KotlinType delegateType,
392                @Nullable ClassDescriptor superCallTarget
393        ) {
394            // TODO this corresponds to default behavior for properties before fixing KT-9717. Is it Ok in general case?
395            // Does not matter for other descriptor kinds.
396            return getAccessor(possiblySubstitutedDescriptor, accessorKind, delegateType, superCallTarget,
397                               /* getterAccessorRequired */ true,
398                               /* setterAccessorRequired */ true);
399        }
400    
401        @SuppressWarnings("unchecked")
402        @NotNull
403        private <D extends CallableMemberDescriptor> D getAccessor(
404                @NotNull D possiblySubstitutedDescriptor,
405                @NotNull FieldAccessorKind accessorKind,
406                @Nullable KotlinType delegateType,
407                @Nullable ClassDescriptor superCallTarget,
408                boolean getterAccessorRequired,
409                boolean setterAccessorRequired
410        ) {
411            if (accessors == null) {
412                accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
413            }
414            if (propertyAccessorFactories == null) {
415                propertyAccessorFactories = new LinkedHashMap<AccessorKey, AccessorForPropertyDescriptorFactory>();
416            }
417    
418            D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
419            AccessorKey key = new AccessorKey(descriptor, superCallTarget);
420    
421            // NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
422            AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key);
423            if (propertyAccessorFactory != null) {
424                return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
425            }
426            AccessorForCallableDescriptor<?> accessor = accessors.get(key);
427            if (accessor != null) {
428                assert accessorKind == FieldAccessorKind.NORMAL ||
429                       accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
430                return (D) accessor;
431            }
432            String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
433            if (descriptor instanceof SimpleFunctionDescriptor) {
434                accessor = new AccessorForFunctionDescriptor(
435                        (FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix
436                );
437            }
438            else if (descriptor instanceof ConstructorDescriptor) {
439                accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallTarget);
440            }
441            else if (descriptor instanceof PropertyDescriptor) {
442                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
443                switch (accessorKind) {
444                    case NORMAL:
445                        propertyAccessorFactory = new AccessorForPropertyDescriptorFactory((PropertyDescriptor) descriptor, contextDescriptor,
446                                                                                           superCallTarget, nameSuffix);
447                        propertyAccessorFactories.put(key, propertyAccessorFactory);
448    
449                        // Record worst case accessor for accessor methods generation.
450                        AccessorForPropertyDescriptor accessorWithGetterAndSetter =
451                                propertyAccessorFactory.getOrCreateAccessorWithSyntheticGetterAndSetter();
452                        accessors.put(key, accessorWithGetterAndSetter);
453    
454                        PropertyDescriptor accessorDescriptor =
455                                propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
456                        return (D) accessorDescriptor;
457                    case IN_CLASS_COMPANION:
458                        accessor = new AccessorForPropertyBackingFieldInClassCompanion(propertyDescriptor, contextDescriptor,
459                                                                                       delegateType, nameSuffix);
460                        break;
461                    case FIELD_FROM_LOCAL:
462                        accessor = new AccessorForPropertyBackingFieldFromLocal(propertyDescriptor, contextDescriptor, nameSuffix);
463                        break;
464                }
465            }
466            else {
467                throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
468            }
469    
470            accessors.put(key, accessor);
471    
472            return (D) accessor;
473        }
474    
475        @Nullable
476        protected StackValue.Field computeOuterExpression() {
477            return null;
478        }
479    
480        public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
481            StackValue myOuter = null;
482            if (closure != null) {
483                EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
484                if (answer != null) {
485                    return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result);
486                }
487    
488                for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
489                    if (aCase.isCase(d)) {
490                        Type classType = state.getTypeMapper().mapType(getThisDescriptor());
491                        StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
492                        if (innerValue == null) {
493                            break;
494                        }
495                        else {
496                            return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
497                        }
498                    }
499                }
500    
501                myOuter = getOuterExpression(result, ignoreNoOuter, false);
502                result = myOuter;
503            }
504    
505            StackValue resultValue;
506            if (myOuter != null && getEnclosingClass() == d) {
507                resultValue = result;
508            } else {
509                resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
510            }
511    
512            if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
513                closure.setCaptureThis();
514            }
515            return resultValue;
516        }
517    
518        @NotNull
519        @ReadOnly
520        public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
521            return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
522        }
523    
524        @SuppressWarnings("unchecked")
525        @NotNull
526        public <D extends CallableMemberDescriptor> D accessibleDescriptor(
527                @NotNull D descriptor,
528                @Nullable ClassDescriptor superCallTarget
529        ) {
530            CodegenContext properContext = getFirstCrossInlineOrNonInlineContext();
531            DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
532            boolean isInliningContext = properContext.isInlineMethodContext();
533            if (!isInliningContext && (
534                    !properContext.hasThisDescriptor() ||
535                    enclosing == properContext.getThisDescriptor() ||
536                    enclosing == properContext.getClassOrPackageParentContext().getContextDescriptor())) {
537                return descriptor;
538            }
539            return (D) properContext.accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
540        }
541    
542        @SuppressWarnings("unchecked")
543        @NotNull
544        private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
545                @NotNull D descriptor,
546                @Nullable ClassDescriptor superCallTarget,
547                boolean withinInliningContext
548        ) {
549            CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
550    
551            DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
552            CodegenContext descriptorContext = findParentContextWithDescriptor(enclosed);
553            if (descriptorContext == null && DescriptorUtils.isCompanionObject(enclosed)) {
554                CodegenContext classContext = findParentContextWithDescriptor(enclosed.getContainingDeclaration());
555                if (classContext instanceof ClassContext) {
556                    descriptorContext = ((ClassContext) classContext).getCompanionObjectContext();
557                }
558            }
559    
560            if (descriptorContext == null &&
561                JavaVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() &&
562                !(descriptor instanceof SamConstructorDescriptor)) {
563                //seems we need static receiver in resolved call
564                descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
565                superCallTarget = (ClassDescriptor) enclosed;
566            }
567    
568            if (descriptorContext == null && withinInliningContext && superCallTarget != null) {
569                //generate super calls within inline function through synthetic accessors
570                descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
571            }
572    
573            if (descriptorContext == null) {
574                return descriptor;
575            }
576            if (descriptor instanceof PropertyDescriptor) {
577                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
578                int propertyAccessFlag = getVisibilityAccessFlag(descriptor);
579    
580                PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
581                int getterAccessFlag = getter == null ? propertyAccessFlag
582                                                      : propertyAccessFlag | getVisibilityAccessFlag(getter);
583                boolean getterAccessorRequired = isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext,
584                                                                    withinInliningContext, superCallTarget != null);
585    
586                PropertySetterDescriptor setter = propertyDescriptor.getSetter();
587                int setterAccessFlag = setter == null ? propertyAccessFlag
588                                                      : propertyAccessFlag | getVisibilityAccessFlag(setter);
589                boolean setterAccessorRequired = isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext,
590                                                                    withinInliningContext, superCallTarget != null);
591    
592                if (!getterAccessorRequired && !setterAccessorRequired) {
593                    return descriptor;
594                }
595                return (D) descriptorContext.getPropertyAccessor(propertyDescriptor, superCallTarget, getterAccessorRequired, setterAccessorRequired);
596            }
597            else {
598                int flag = getVisibilityAccessFlag(unwrappedDescriptor);
599                if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext, withinInliningContext, superCallTarget != null)) {
600                    return descriptor;
601                }
602                return (D) descriptorContext.getAccessor(descriptor, superCallTarget);
603            }
604        }
605    
606        private static boolean isAccessorRequired(
607                int accessFlag,
608                @NotNull CallableMemberDescriptor unwrappedDescriptor,
609                @NotNull CodegenContext descriptorContext,
610                boolean withinInline,
611                boolean isSuperCall
612        ) {
613            if (AnnotationUtilKt.isInlineOnly(unwrappedDescriptor)) return false;
614    
615            return isSuperCall && withinInline ||
616                   (accessFlag & ACC_PRIVATE) != 0 ||
617                   ((accessFlag & ACC_PROTECTED) != 0 &&
618                    (withinInline || !isInSamePackage(unwrappedDescriptor, descriptorContext.getContextDescriptor())));
619        }
620    
621        private static boolean isInSamePackage(DeclarationDescriptor descriptor1, DeclarationDescriptor descriptor2) {
622            PackageFragmentDescriptor package1 =
623                    DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor.class, false);
624            PackageFragmentDescriptor package2 =
625                    DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor.class, false);
626    
627            return package2 != null && package1 != null &&
628                   package1.getFqName().equals(package2.getFqName());
629        }
630    
631        private void addChild(@NotNull CodegenContext child) {
632            if (shouldAddChild(child)) {
633                if (childContexts == null) {
634                    childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
635                }
636                DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
637                childContexts.put(childContextDescriptor, child);
638            }
639        }
640    
641        protected boolean shouldAddChild(@NotNull CodegenContext child) {
642            return DescriptorUtils.isCompanionObject(child.contextDescriptor);
643        }
644    
645        @Nullable
646        protected CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
647            return childContexts == null ? null : childContexts.get(child);
648        }
649    
650        private static boolean isStaticField(@NotNull StackValue value) {
651            return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
652        }
653    
654        public boolean isInlineMethodContext() {
655            return false;
656        }
657    
658        @NotNull
659        public CodegenContext getFirstCrossInlineOrNonInlineContext() {
660            return this;
661        }
662    }