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