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.kotlin.codegen.*;
023    import org.jetbrains.kotlin.codegen.binding.MutableClosure;
024    import org.jetbrains.kotlin.codegen.state.GenerationState;
025    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
026    import org.jetbrains.kotlin.descriptors.*;
027    import org.jetbrains.kotlin.load.java.JavaVisibilities;
028    import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
029    import org.jetbrains.kotlin.psi.KtFile;
030    import org.jetbrains.kotlin.resolve.BindingContext;
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.resolve.BindingContext.NEED_SYNTHETIC_ACCESSOR;
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        @NotNull
271        public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
272            if (descriptor.isCompanionObject()) {
273                CodegenContext companionContext = this.findChildContext(descriptor);
274                if (companionContext != null) {
275                    assert companionContext.getContextKind() == kind : "Kinds should be same, but: " +
276                                                                       companionContext.getContextKind() + "!= " + kind;
277                    return (ClassContext) companionContext;
278                }
279            }
280            ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
281    
282            //We can't call descriptor.getCompanionObjectDescriptor() on light class generation
283            // because it triggers companion light class generation via putting it to BindingContext.CLASS
284            // (so MemberCodegen doesn't skip it in genClassOrObject).
285            if (state.getTypeMapper().getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES &&
286                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, false);
302        }
303    
304        @NotNull
305        public MethodContext intoInlinedLambda(FunctionDescriptor descriptor) {
306            return new MethodContext(descriptor, getContextKind(), this, null, true);
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        public <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 getAccessor(
375                @NotNull D possiblySubstitutedDescriptor,
376                @NotNull FieldAccessorKind accessorKind,
377                @Nullable KotlinType delegateType,
378                @Nullable ClassDescriptor superCallTarget
379        ) {
380            // TODO this corresponds to default behavior for properties before fixing KT-9717. Is it Ok in general case?
381            // Does not matter for other descriptor kinds.
382            return getAccessor(possiblySubstitutedDescriptor, accessorKind, delegateType, superCallTarget,
383                               /* getterAccessorRequired */ true,
384                               /* setterAccessorRequired */ true);
385        }
386    
387        @SuppressWarnings("unchecked")
388        @NotNull
389        private <D extends CallableMemberDescriptor> D getAccessor(
390                @NotNull D possiblySubstitutedDescriptor,
391                @NotNull FieldAccessorKind accessorKind,
392                @Nullable KotlinType delegateType,
393                @Nullable ClassDescriptor superCallTarget,
394                boolean getterAccessorRequired,
395                boolean setterAccessorRequired
396        ) {
397            if (accessors == null) {
398                accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
399            }
400            if (propertyAccessorFactories == null) {
401                propertyAccessorFactories = new LinkedHashMap<AccessorKey, AccessorForPropertyDescriptorFactory>();
402            }
403    
404            D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
405            AccessorKey key = new AccessorKey(descriptor, superCallTarget);
406    
407            // NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
408            AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key);
409            if (propertyAccessorFactory != null) {
410                return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
411            }
412            AccessorForCallableDescriptor<?> accessor = accessors.get(key);
413            if (accessor != null) {
414                assert accessorKind == FieldAccessorKind.NORMAL ||
415                       accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
416                return (D) accessor;
417            }
418            String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
419            if (descriptor instanceof SimpleFunctionDescriptor) {
420                accessor = new AccessorForFunctionDescriptor(
421                        (FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix
422                );
423            }
424            else if (descriptor instanceof ConstructorDescriptor) {
425                accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallTarget);
426            }
427            else if (descriptor instanceof PropertyDescriptor) {
428                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
429                switch (accessorKind) {
430                    case NORMAL:
431                        propertyAccessorFactory = new AccessorForPropertyDescriptorFactory((PropertyDescriptor) descriptor, contextDescriptor,
432                                                                                           superCallTarget, nameSuffix);
433                        propertyAccessorFactories.put(key, propertyAccessorFactory);
434    
435                        // Record worst case accessor for accessor methods generation.
436                        AccessorForPropertyDescriptor accessorWithGetterAndSetter =
437                                propertyAccessorFactory.getOrCreateAccessorWithSyntheticGetterAndSetter();
438                        accessors.put(key, accessorWithGetterAndSetter);
439    
440                        PropertyDescriptor accessorDescriptor =
441                                propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
442                        return (D) accessorDescriptor;
443                    case IN_CLASS_COMPANION:
444                        accessor = new AccessorForPropertyBackingFieldInClassCompanion(propertyDescriptor, contextDescriptor,
445                                                                                       delegateType, nameSuffix);
446                        break;
447                    case FIELD_FROM_LOCAL:
448                        accessor = new AccessorForPropertyBackingFieldFromLocal(propertyDescriptor, contextDescriptor, nameSuffix);
449                        break;
450                }
451            }
452            else {
453                throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
454            }
455    
456            accessors.put(key, accessor);
457    
458            return (D) accessor;
459        }
460    
461        @Nullable
462        protected StackValue.Field computeOuterExpression() {
463            return null;
464        }
465    
466        public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
467            StackValue myOuter = null;
468            if (closure != null) {
469                EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
470                if (answer != null) {
471                    return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result);
472                }
473    
474                for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
475                    if (aCase.isCase(d)) {
476                        Type classType = state.getTypeMapper().mapType(getThisDescriptor());
477                        StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
478                        if (innerValue == null) {
479                            break;
480                        }
481                        else {
482                            return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
483                        }
484                    }
485                }
486    
487                myOuter = getOuterExpression(result, ignoreNoOuter, false);
488                result = myOuter;
489            }
490    
491            StackValue resultValue;
492            if (myOuter != null && getEnclosingClass() == d) {
493                resultValue = result;
494            } else {
495                resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
496            }
497    
498            if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
499                closure.setCaptureThis();
500            }
501            return resultValue;
502        }
503    
504        @NotNull
505        public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
506            return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
507        }
508    
509        @NotNull
510        public <D extends CallableMemberDescriptor> D accessibleDescriptor(
511                @NotNull D descriptor,
512                @Nullable ClassDescriptor superCallTarget
513        ) {
514            DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
515            boolean isInliningContext = isInlineMethodContext();
516            if (!isInliningContext && (
517                    !hasThisDescriptor() ||
518                    enclosing == getThisDescriptor() ||
519                    enclosing == getClassOrPackageParentContext().getContextDescriptor())) {
520                return descriptor;
521            }
522    
523            return accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
524        }
525    
526        public void recordSyntheticAccessorIfNeeded(@NotNull CallableMemberDescriptor descriptor, @NotNull BindingContext bindingContext) {
527            if (hasThisDescriptor() && Boolean.TRUE.equals(bindingContext.get(NEED_SYNTHETIC_ACCESSOR, descriptor))) {
528                // Not a super call because neither constructors nor private members can be targets of super calls
529                accessibleDescriptorIfNeeded(descriptor, /* superCallTarget = */ null, false);
530            }
531        }
532    
533        @SuppressWarnings("unchecked")
534        @NotNull
535        private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
536                @NotNull D descriptor,
537                @Nullable ClassDescriptor superCallTarget,
538                boolean withinInliningContext
539        ) {
540            CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
541    
542            DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
543            CodegenContext descriptorContext = findParentContextWithDescriptor(enclosed);
544            if (descriptorContext == null && DescriptorUtils.isCompanionObject(enclosed)) {
545                CodegenContext classContext = findParentContextWithDescriptor(enclosed.getContainingDeclaration());
546                if (classContext instanceof ClassContext) {
547                    descriptorContext = ((ClassContext) classContext).getCompanionObjectContext();
548                }
549            }
550    
551            if (descriptorContext == null &&
552                JavaVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() &&
553                !(descriptor instanceof SamConstructorDescriptor)) {
554                //seems we need static receiver in resolved call
555                descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
556                superCallTarget = (ClassDescriptor) enclosed;
557            }
558    
559            if (descriptorContext == null && withinInliningContext && superCallTarget != null) {
560                //generate super calls within inline function through synthetic accessors
561                descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
562            }
563    
564            if (descriptorContext == null) {
565                return descriptor;
566            }
567            if (descriptor instanceof PropertyDescriptor) {
568                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
569                int propertyAccessFlag = getVisibilityAccessFlag(descriptor);
570    
571                PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
572                int getterAccessFlag = getter == null ? propertyAccessFlag
573                                                      : propertyAccessFlag | getVisibilityAccessFlag(getter);
574                boolean getterAccessorRequired = isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext,
575                                                                    withinInliningContext, superCallTarget != null);
576    
577                PropertySetterDescriptor setter = propertyDescriptor.getSetter();
578                int setterAccessFlag = setter == null ? propertyAccessFlag
579                                                      : propertyAccessFlag | getVisibilityAccessFlag(setter);
580                boolean setterAccessorRequired = isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext,
581                                                                    withinInliningContext, superCallTarget != null);
582    
583                if (!getterAccessorRequired && !setterAccessorRequired) {
584                    return descriptor;
585                }
586                return (D) descriptorContext.getPropertyAccessor(propertyDescriptor, superCallTarget, getterAccessorRequired, setterAccessorRequired);
587            }
588            else {
589                int flag = getVisibilityAccessFlag(unwrappedDescriptor);
590                if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext, withinInliningContext, superCallTarget != null)) {
591                    return descriptor;
592                }
593                return (D) descriptorContext.getAccessor(descriptor, superCallTarget);
594            }
595        }
596    
597        private static boolean isAccessorRequired(
598                int accessFlag,
599                @NotNull CallableMemberDescriptor unwrappedDescriptor,
600                @NotNull CodegenContext descriptorContext,
601                boolean withinInline,
602                boolean isSuperCall
603        ) {
604            return isSuperCall && withinInline ||
605                   (accessFlag & ACC_PRIVATE) != 0 ||
606                   ((accessFlag & ACC_PROTECTED) != 0 &&
607                    (withinInline || !isInSamePackage(unwrappedDescriptor, descriptorContext.getContextDescriptor())));
608        }
609    
610        private static boolean isInSamePackage(DeclarationDescriptor descriptor1, DeclarationDescriptor descriptor2) {
611            PackageFragmentDescriptor package1 =
612                    DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor.class, false);
613            PackageFragmentDescriptor package2 =
614                    DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor.class, false);
615    
616            return package2 != null && package1 != null &&
617                   package1.getFqName().equals(package2.getFqName());
618        }
619    
620        private void addChild(@NotNull CodegenContext child) {
621            if (shouldAddChild(child)) {
622                if (childContexts == null) {
623                    childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
624                }
625                DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
626                childContexts.put(childContextDescriptor, child);
627            }
628        }
629    
630        protected boolean shouldAddChild(@NotNull CodegenContext child) {
631            return DescriptorUtils.isCompanionObject(child.contextDescriptor);
632        }
633    
634        @Nullable
635        public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
636            return childContexts == null ? null : childContexts.get(child);
637        }
638    
639        private static boolean isStaticField(@NotNull StackValue value) {
640            return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
641        }
642    
643        private boolean isInsideInliningContext() {
644            CodegenContext current = this;
645            while (current != null) {
646                if (current instanceof MethodContext && ((MethodContext) current).isInlineFunction()) {
647                    return true;
648                }
649                current = current.getParentContext();
650            }
651            return false;
652        }
653    
654        private boolean isInlineMethodContext() {
655            return this instanceof MethodContext && ((MethodContext) this).isInlineFunction();
656        }
657    }