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.KotlinTypeMapper;
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 MultifileClassPartContext intoMultifileClassPart(
254                @NotNull PackageFragmentDescriptor descriptor,
255                @NotNull Type multifileClassType,
256                @NotNull Type filePartType,
257                @NotNull Type filePartInitializerType,
258                @NotNull KtFile sourceFile
259        ) {
260            return new MultifileClassPartContext(descriptor, this, multifileClassType, filePartType, filePartInitializerType, sourceFile);
261        }
262    
263        @NotNull
264        public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClass(
265                @NotNull PackageFragmentDescriptor descriptor,
266                @NotNull Type multifileClassType,
267                @NotNull Type filePartType
268        ) {
269            return new MultifileClassFacadeContext(descriptor, this, multifileClassType, filePartType);
270        }
271    
272        public ClassContext intoDefaultImplsClass(ClassDescriptor descriptor, ClassContext interfaceContext, GenerationState state) {
273            return new DefaultImplsClassContext(state.getTypeMapper(), descriptor, OwnerKind.DEFAULT_IMPLS, this, null, interfaceContext);
274        }
275    
276        @NotNull
277        public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
278            if (descriptor.isCompanionObject()) {
279                CodegenContext companionContext = this.findChildContext(descriptor);
280                if (companionContext != null) {
281                    assert companionContext.getContextKind() == kind : "Kinds should be same, but: " +
282                                                                       companionContext.getContextKind() + "!= " + kind;
283                    return (ClassContext) companionContext;
284                }
285            }
286            ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
287    
288            if (descriptor.getCompanionObjectDescriptor() != null) {
289                //We need to create companion object context ahead of time
290                // because otherwise we can't generate synthetic accessor for private members in companion object
291                classContext.intoClass(descriptor.getCompanionObjectDescriptor(), OwnerKind.IMPLEMENTATION, state);
292            }
293            return classContext;
294        }
295    
296        @NotNull
297        public ClassContext intoAnonymousClass(@NotNull ClassDescriptor descriptor, @NotNull ExpressionCodegen codegen, @NotNull OwnerKind ownerKind) {
298            return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen);
299        }
300    
301        @NotNull
302        public MethodContext intoFunction(FunctionDescriptor descriptor) {
303            return new MethodContext(descriptor, getContextKind(), this, null);
304        }
305    
306        @NotNull
307        public MethodContext intoInlinedLambda(FunctionDescriptor descriptor, boolean isCrossInline) {
308            return new InlineLambdaContext(descriptor, getContextKind(), this, null, isCrossInline);
309        }
310    
311        @NotNull
312        public ConstructorContext intoConstructor(@NotNull ConstructorDescriptor descriptor) {
313            return new ConstructorContext(descriptor, getContextKind(), this, closure);
314        }
315    
316        @NotNull
317        public ScriptContext intoScript(
318                @NotNull ScriptDescriptor script,
319                @NotNull List<ScriptDescriptor> earlierScripts,
320                @NotNull ClassDescriptor classDescriptor,
321                @NotNull KotlinTypeMapper typeMapper
322        ) {
323            return new ScriptContext(typeMapper, script, earlierScripts, classDescriptor, this);
324        }
325    
326        @NotNull
327        public ClosureContext intoClosure(
328                @NotNull FunctionDescriptor funDescriptor,
329                @NotNull LocalLookup localLookup,
330                @NotNull KotlinTypeMapper typeMapper
331        ) {
332            return new ClosureContext(typeMapper, funDescriptor, this, localLookup);
333        }
334    
335        @Nullable
336        public CodegenContext getParentContext() {
337            return parentContext;
338        }
339    
340        public ClassDescriptor getEnclosingClass() {
341            CodegenContext cur = getParentContext();
342            while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) {
343                cur = cur.getParentContext();
344            }
345    
346            return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor();
347        }
348    
349        @Nullable
350        public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) {
351            CodegenContext c = this;
352            while (c != null) {
353                if (c.getContextDescriptor() == descriptor) break;
354                c = c.getParentContext();
355            }
356            return c;
357        }
358    
359        @NotNull
360        private PropertyDescriptor getPropertyAccessor(
361                @NotNull PropertyDescriptor propertyDescriptor,
362                @Nullable ClassDescriptor superCallTarget,
363                boolean getterAccessorRequired,
364                boolean setterAccessorRequired
365        ) {
366            return getAccessor(propertyDescriptor, FieldAccessorKind.NORMAL, null, superCallTarget, getterAccessorRequired, setterAccessorRequired);
367        }
368    
369        @NotNull
370        private <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
371            return getAccessor(descriptor, FieldAccessorKind.NORMAL, null, superCallTarget);
372        }
373    
374        @SuppressWarnings("unchecked")
375        @NotNull
376        public <D extends CallableMemberDescriptor> D getAccessorForSuperCallIfNeeded(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
377            if (superCallTarget != null && !isJvmInterface(descriptor.getContainingDeclaration())) {
378                CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext();
379                CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget);
380                assert c != null : "Couldn't find a context for a super-call: " + descriptor;
381                if (c != afterInline.getParentContext()) {
382                    return (D) c.getAccessor(descriptor, superCallTarget);
383                }
384            }
385            return descriptor;
386        }
387    
388        @NotNull
389        public <D extends CallableMemberDescriptor> D getAccessor(
390                @NotNull D possiblySubstitutedDescriptor,
391                @NotNull FieldAccessorKind accessorKind,
392                @Nullable KotlinType delegateType,
393                @Nullable ClassDescriptor superCallTarget
394        ) {
395            // TODO this corresponds to default behavior for properties before fixing KT-9717. Is it Ok in general case?
396            // Does not matter for other descriptor kinds.
397            return getAccessor(possiblySubstitutedDescriptor, accessorKind, delegateType, superCallTarget,
398                               /* getterAccessorRequired */ true,
399                               /* setterAccessorRequired */ true);
400        }
401    
402        @SuppressWarnings("unchecked")
403        @NotNull
404        private <D extends CallableMemberDescriptor> D getAccessor(
405                @NotNull D possiblySubstitutedDescriptor,
406                @NotNull FieldAccessorKind accessorKind,
407                @Nullable KotlinType delegateType,
408                @Nullable ClassDescriptor superCallTarget,
409                boolean getterAccessorRequired,
410                boolean setterAccessorRequired
411        ) {
412            if (accessors == null) {
413                accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
414            }
415            if (propertyAccessorFactories == null) {
416                propertyAccessorFactories = new LinkedHashMap<AccessorKey, AccessorForPropertyDescriptorFactory>();
417            }
418    
419            D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
420            AccessorKey key = new AccessorKey(descriptor, superCallTarget);
421    
422            // NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
423            AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key);
424            if (propertyAccessorFactory != null) {
425                return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
426            }
427            AccessorForCallableDescriptor<?> accessor = accessors.get(key);
428            if (accessor != null) {
429                assert accessorKind == FieldAccessorKind.NORMAL ||
430                       accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
431                return (D) accessor;
432            }
433            String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
434            if (descriptor instanceof SimpleFunctionDescriptor) {
435                accessor = new AccessorForFunctionDescriptor(
436                        (FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix
437                );
438            }
439            else if (descriptor instanceof ConstructorDescriptor) {
440                accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallTarget);
441            }
442            else if (descriptor instanceof PropertyDescriptor) {
443                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
444                switch (accessorKind) {
445                    case NORMAL:
446                        propertyAccessorFactory = new AccessorForPropertyDescriptorFactory((PropertyDescriptor) descriptor, contextDescriptor,
447                                                                                           superCallTarget, nameSuffix);
448                        propertyAccessorFactories.put(key, propertyAccessorFactory);
449    
450                        // Record worst case accessor for accessor methods generation.
451                        AccessorForPropertyDescriptor accessorWithGetterAndSetter =
452                                propertyAccessorFactory.getOrCreateAccessorWithSyntheticGetterAndSetter();
453                        accessors.put(key, accessorWithGetterAndSetter);
454    
455                        PropertyDescriptor accessorDescriptor =
456                                propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
457                        return (D) accessorDescriptor;
458                    case IN_CLASS_COMPANION:
459                        accessor = new AccessorForPropertyBackingFieldInClassCompanion(propertyDescriptor, contextDescriptor,
460                                                                                       delegateType, nameSuffix);
461                        break;
462                    case FIELD_FROM_LOCAL:
463                        accessor = new AccessorForPropertyBackingFieldFromLocal(propertyDescriptor, contextDescriptor, nameSuffix);
464                        break;
465                }
466            }
467            else {
468                throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
469            }
470    
471            accessors.put(key, accessor);
472    
473            return (D) accessor;
474        }
475    
476        @Nullable
477        protected StackValue.Field computeOuterExpression() {
478            return null;
479        }
480    
481        public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
482            StackValue myOuter = null;
483            if (closure != null) {
484                EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
485                if (answer != null) {
486                    return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result);
487                }
488    
489                for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
490                    if (aCase.isCase(d)) {
491                        Type classType = state.getTypeMapper().mapType(getThisDescriptor());
492                        StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
493                        if (innerValue == null) {
494                            break;
495                        }
496                        else {
497                            return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
498                        }
499                    }
500                }
501    
502                myOuter = getOuterExpression(result, ignoreNoOuter, false);
503                result = myOuter;
504            }
505    
506            StackValue resultValue;
507            if (myOuter != null && getEnclosingClass() == d) {
508                resultValue = result;
509            } else {
510                resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
511            }
512    
513            if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
514                closure.setCaptureThis();
515            }
516            return resultValue;
517        }
518    
519        @NotNull
520        @ReadOnly
521        public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
522            return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
523        }
524    
525        @SuppressWarnings("unchecked")
526        @NotNull
527        public <D extends CallableMemberDescriptor> D accessibleDescriptor(
528                @NotNull D descriptor,
529                @Nullable ClassDescriptor superCallTarget
530        ) {
531            CodegenContext properContext = getFirstCrossInlineOrNonInlineContext();
532            DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
533            boolean isInliningContext = properContext.isInlineMethodContext();
534            if (!isInliningContext && (
535                    !properContext.hasThisDescriptor() ||
536                    enclosing == properContext.getThisDescriptor() ||
537                    enclosing == properContext.getClassOrPackageParentContext().getContextDescriptor())) {
538                return descriptor;
539            }
540            return (D) properContext.accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
541        }
542    
543        @SuppressWarnings("unchecked")
544        @NotNull
545        private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
546                @NotNull D descriptor,
547                @Nullable ClassDescriptor superCallTarget,
548                boolean withinInliningContext
549        ) {
550            CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
551    
552            DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
553            CodegenContext descriptorContext = findParentContextWithDescriptor(enclosed);
554            if (descriptorContext == null && DescriptorUtils.isCompanionObject(enclosed)) {
555                CodegenContext classContext = findParentContextWithDescriptor(enclosed.getContainingDeclaration());
556                if (classContext instanceof ClassContext) {
557                    descriptorContext = ((ClassContext) classContext).getCompanionObjectContext();
558                }
559            }
560    
561            if (descriptorContext == null &&
562                JavaVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() &&
563                !(descriptor instanceof SamConstructorDescriptor)) {
564                //seems we need static receiver in resolved call
565                descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
566                superCallTarget = (ClassDescriptor) enclosed;
567            }
568    
569            if (descriptorContext == null && withinInliningContext && superCallTarget != null) {
570                //generate super calls within inline function through synthetic accessors
571                descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
572            }
573    
574            if (descriptorContext == null) {
575                return descriptor;
576            }
577            if (descriptor instanceof PropertyDescriptor) {
578                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
579                int propertyAccessFlag = getVisibilityAccessFlag(descriptor);
580    
581                PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
582                int getterAccessFlag = getter == null ? propertyAccessFlag
583                                                      : propertyAccessFlag | getVisibilityAccessFlag(getter);
584                boolean getterAccessorRequired = isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext,
585                                                                    withinInliningContext, superCallTarget != null);
586    
587                PropertySetterDescriptor setter = propertyDescriptor.getSetter();
588                int setterAccessFlag = setter == null ? propertyAccessFlag
589                                                      : propertyAccessFlag | getVisibilityAccessFlag(setter);
590                boolean setterAccessorRequired = isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext,
591                                                                    withinInliningContext, superCallTarget != null);
592    
593                if (!getterAccessorRequired && !setterAccessorRequired) {
594                    return descriptor;
595                }
596                return (D) descriptorContext.getPropertyAccessor(propertyDescriptor, superCallTarget, getterAccessorRequired, setterAccessorRequired);
597            }
598            else {
599                int flag = getVisibilityAccessFlag(unwrappedDescriptor);
600                if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext, withinInliningContext, superCallTarget != null)) {
601                    return descriptor;
602                }
603                return (D) descriptorContext.getAccessor(descriptor, superCallTarget);
604            }
605        }
606    
607        private static boolean isAccessorRequired(
608                int accessFlag,
609                @NotNull CallableMemberDescriptor unwrappedDescriptor,
610                @NotNull CodegenContext descriptorContext,
611                boolean withinInline,
612                boolean isSuperCall
613        ) {
614            if (AnnotationUtilKt.isInlineOnlyOrReified(unwrappedDescriptor)) return false;
615    
616            return isSuperCall && withinInline ||
617                   (accessFlag & ACC_PRIVATE) != 0 ||
618                   ((accessFlag & ACC_PROTECTED) != 0 &&
619                    (withinInline || !isInSamePackage(unwrappedDescriptor, descriptorContext.getContextDescriptor())));
620        }
621    
622        private static boolean isInSamePackage(DeclarationDescriptor descriptor1, DeclarationDescriptor descriptor2) {
623            PackageFragmentDescriptor package1 =
624                    DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor.class, false);
625            PackageFragmentDescriptor package2 =
626                    DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor.class, false);
627    
628            return package2 != null && package1 != null &&
629                   package1.getFqName().equals(package2.getFqName());
630        }
631    
632        private void addChild(@NotNull CodegenContext child) {
633            if (shouldAddChild(child)) {
634                if (childContexts == null) {
635                    childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
636                }
637                DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
638                childContexts.put(childContextDescriptor, child);
639            }
640        }
641    
642        protected boolean shouldAddChild(@NotNull CodegenContext child) {
643            return DescriptorUtils.isCompanionObject(child.contextDescriptor);
644        }
645    
646        @Nullable
647        protected CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
648            return childContexts == null ? null : childContexts.get(child);
649        }
650    
651        private static boolean isStaticField(@NotNull StackValue value) {
652            return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
653        }
654    
655        public boolean isInlineMethodContext() {
656            return false;
657        }
658    
659        @NotNull
660        public CodegenContext getFirstCrossInlineOrNonInlineContext() {
661            return this;
662        }
663    }