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        ) {
320            return new ScriptContext(script, earlierScripts, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure);
321        }
322    
323        @NotNull
324        public ClosureContext intoClosure(
325                @NotNull FunctionDescriptor funDescriptor,
326                @NotNull LocalLookup localLookup,
327                @NotNull JetTypeMapper typeMapper
328        ) {
329            return new ClosureContext(typeMapper, funDescriptor, this, localLookup);
330        }
331    
332        @Nullable
333        public CodegenContext getParentContext() {
334            return parentContext;
335        }
336    
337        public ClassDescriptor getEnclosingClass() {
338            CodegenContext cur = getParentContext();
339            while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) {
340                cur = cur.getParentContext();
341            }
342    
343            return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor();
344        }
345    
346        @Nullable
347        public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) {
348            CodegenContext c = this;
349            while (c != null) {
350                if (c.getContextDescriptor() == descriptor) break;
351                c = c.getParentContext();
352            }
353            return c;
354        }
355    
356        @NotNull
357        private PropertyDescriptor getPropertyAccessor(
358                @NotNull PropertyDescriptor propertyDescriptor,
359                @Nullable ClassDescriptor superCallTarget,
360                boolean getterAccessorRequired,
361                boolean setterAccessorRequired
362        ) {
363            return getAccessor(propertyDescriptor, FieldAccessorKind.NORMAL, null, superCallTarget, getterAccessorRequired, setterAccessorRequired);
364        }
365    
366        @NotNull
367        public <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
368            return getAccessor(descriptor, FieldAccessorKind.NORMAL, null, superCallTarget);
369        }
370    
371        @SuppressWarnings("unchecked")
372        @NotNull
373        public <D extends CallableMemberDescriptor> D getAccessor(
374                @NotNull D possiblySubstitutedDescriptor,
375                @NotNull FieldAccessorKind accessorKind,
376                @Nullable KotlinType delegateType,
377                @Nullable ClassDescriptor superCallTarget
378        ) {
379            // TODO this corresponds to default behavior for properties before fixing KT-9717. Is it Ok in general case?
380            // Does not matter for other descriptor kinds.
381            return getAccessor(possiblySubstitutedDescriptor, accessorKind, delegateType, superCallTarget,
382                               /* getterAccessorRequired */ true,
383                               /* setterAccessorRequired */ true);
384        }
385    
386        @SuppressWarnings("unchecked")
387        @NotNull
388        private <D extends CallableMemberDescriptor> D getAccessor(
389                @NotNull D possiblySubstitutedDescriptor,
390                @NotNull FieldAccessorKind accessorKind,
391                @Nullable KotlinType delegateType,
392                @Nullable ClassDescriptor superCallTarget,
393                boolean getterAccessorRequired,
394                boolean setterAccessorRequired
395        ) {
396            if (accessors == null) {
397                accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
398            }
399            if (propertyAccessorFactories == null) {
400                propertyAccessorFactories = new LinkedHashMap<AccessorKey, AccessorForPropertyDescriptorFactory>();
401            }
402    
403            D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
404            AccessorKey key = new AccessorKey(descriptor, superCallTarget);
405    
406            // NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
407            AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key);
408            if (propertyAccessorFactory != null) {
409                return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
410            }
411            AccessorForCallableDescriptor<?> accessor = accessors.get(key);
412            if (accessor != null) {
413                assert accessorKind == FieldAccessorKind.NORMAL ||
414                       accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
415                return (D) accessor;
416            }
417            String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
418            if (descriptor instanceof SimpleFunctionDescriptor) {
419                accessor = new AccessorForFunctionDescriptor(
420                        (FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix
421                );
422            }
423            else if (descriptor instanceof ConstructorDescriptor) {
424                accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallTarget);
425            }
426            else if (descriptor instanceof PropertyDescriptor) {
427                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
428                switch (accessorKind) {
429                    case NORMAL:
430                        propertyAccessorFactory = new AccessorForPropertyDescriptorFactory((PropertyDescriptor) descriptor, contextDescriptor,
431                                                                                           superCallTarget, nameSuffix);
432                        propertyAccessorFactories.put(key, propertyAccessorFactory);
433    
434                        // Record worst case accessor for accessor methods generation.
435                        AccessorForPropertyDescriptor accessorWithGetterAndSetter =
436                                propertyAccessorFactory.getOrCreateAccessorWithSyntheticGetterAndSetter();
437                        accessors.put(key, accessorWithGetterAndSetter);
438    
439                        PropertyDescriptor accessorDescriptor =
440                                propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
441                        return (D) accessorDescriptor;
442                    case IN_CLASS_COMPANION:
443                        accessor = new AccessorForPropertyBackingFieldInClassCompanion(propertyDescriptor, contextDescriptor,
444                                                                                       delegateType, nameSuffix);
445                        break;
446                    case FIELD_FROM_LOCAL:
447                        accessor = new AccessorForPropertyBackingFieldFromLocal(propertyDescriptor, contextDescriptor, nameSuffix);
448                        break;
449                }
450            }
451            else {
452                throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
453            }
454    
455            accessors.put(key, accessor);
456    
457            return (D) accessor;
458        }
459    
460        @Nullable
461        protected StackValue.Field computeOuterExpression() {
462            return null;
463        }
464    
465        public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
466            StackValue myOuter = null;
467            if (closure != null) {
468                EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
469                if (answer != null) {
470                    return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result);
471                }
472    
473                for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
474                    if (aCase.isCase(d)) {
475                        Type classType = state.getTypeMapper().mapType(getThisDescriptor());
476                        StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
477                        if (innerValue == null) {
478                            break;
479                        }
480                        else {
481                            return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
482                        }
483                    }
484                }
485    
486                myOuter = getOuterExpression(result, ignoreNoOuter, false);
487                result = myOuter;
488            }
489    
490            StackValue resultValue;
491            if (myOuter != null && getEnclosingClass() == d) {
492                resultValue = result;
493            } else {
494                resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
495            }
496    
497            if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
498                closure.setCaptureThis();
499            }
500            return resultValue;
501        }
502    
503        @NotNull
504        public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
505            return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
506        }
507    
508        @NotNull
509        public <D extends CallableMemberDescriptor> D accessibleDescriptor(
510                @NotNull D descriptor,
511                @Nullable ClassDescriptor superCallTarget
512        ) {
513            DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
514            if (!isInlineMethodContext() && (
515                    !hasThisDescriptor() ||
516                    enclosing == getThisDescriptor() ||
517                    enclosing == getClassOrPackageParentContext().getContextDescriptor())) {
518                return descriptor;
519            }
520    
521            return accessibleDescriptorIfNeeded(descriptor, superCallTarget);
522        }
523    
524        public void recordSyntheticAccessorIfNeeded(@NotNull CallableMemberDescriptor descriptor, @NotNull BindingContext bindingContext) {
525            if (hasThisDescriptor() && Boolean.TRUE.equals(bindingContext.get(NEED_SYNTHETIC_ACCESSOR, descriptor))) {
526                // Not a super call because neither constructors nor private members can be targets of super calls
527                accessibleDescriptorIfNeeded(descriptor, /* superCallTarget = */ null);
528            }
529        }
530    
531        @SuppressWarnings("unchecked")
532        @NotNull
533        private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
534                @NotNull D descriptor,
535                @Nullable ClassDescriptor superCallTarget
536        ) {
537            CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
538    
539            DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
540            CodegenContext descriptorContext = findParentContextWithDescriptor(enclosed);
541            if (descriptorContext == null && DescriptorUtils.isCompanionObject(enclosed)) {
542                CodegenContext classContext = findParentContextWithDescriptor(enclosed.getContainingDeclaration());
543                if (classContext instanceof ClassContext) {
544                    descriptorContext = ((ClassContext) classContext).getCompanionObjectContext();
545                }
546            }
547    
548            if (descriptorContext == null &&
549                JavaVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() &&
550                !(descriptor instanceof SamConstructorDescriptor)) {
551                //seems we need static receiver in resolved call
552                descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
553                superCallTarget = (ClassDescriptor) enclosed;
554            }
555    
556            if (descriptorContext == null) {
557                return descriptor;
558            }
559    
560            if (descriptor instanceof PropertyDescriptor) {
561                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
562                int propertyAccessFlag = getVisibilityAccessFlag(descriptor);
563    
564                PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
565                int getterAccessFlag = getter == null ? propertyAccessFlag
566                                                      : propertyAccessFlag | getVisibilityAccessFlag(getter);
567                boolean getterAccessorRequired = isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext);
568    
569                PropertySetterDescriptor setter = propertyDescriptor.getSetter();
570                int setterAccessFlag = setter == null ? propertyAccessFlag
571                                                      : propertyAccessFlag | getVisibilityAccessFlag(setter);
572                boolean setterAccessorRequired = isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext);
573    
574                if (!getterAccessorRequired && !setterAccessorRequired) {
575                    return descriptor;
576                }
577                return (D) descriptorContext.getPropertyAccessor(propertyDescriptor, superCallTarget, getterAccessorRequired, setterAccessorRequired);
578            }
579            else {
580                int flag = getVisibilityAccessFlag(unwrappedDescriptor);
581                if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext)) {
582                    return descriptor;
583                }
584                return (D) descriptorContext.getAccessor(descriptor, superCallTarget);
585            }
586        }
587    
588        private static boolean isAccessorRequired(
589                int accessFlag,
590                @NotNull CallableMemberDescriptor unwrappedDescriptor,
591                @NotNull CodegenContext descriptorContext
592        ) {
593            return (accessFlag & ACC_PRIVATE) != 0 ||
594                   ((accessFlag & ACC_PROTECTED) != 0 && !isInSamePackage(unwrappedDescriptor, descriptorContext.getContextDescriptor()));
595        }
596    
597        private static boolean isInSamePackage(DeclarationDescriptor descriptor1, DeclarationDescriptor descriptor2) {
598            PackageFragmentDescriptor package1 =
599                    DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor.class, false);
600            PackageFragmentDescriptor package2 =
601                    DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor.class, false);
602    
603            return package2 != null && package1 != null &&
604                   package1.getFqName().equals(package2.getFqName());
605        }
606    
607        private void addChild(@NotNull CodegenContext child) {
608            if (shouldAddChild(child)) {
609                if (childContexts == null) {
610                    childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
611                }
612                DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
613                childContexts.put(childContextDescriptor, child);
614            }
615        }
616    
617        protected boolean shouldAddChild(@NotNull CodegenContext child) {
618            return DescriptorUtils.isCompanionObject(child.contextDescriptor);
619        }
620    
621        @Nullable
622        public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
623            return childContexts == null ? null : childContexts.get(child);
624        }
625    
626        private static boolean isStaticField(@NotNull StackValue value) {
627            return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
628        }
629    
630        private boolean isInsideInliningContext() {
631            CodegenContext current = this;
632            while (current != null) {
633                if (current instanceof MethodContext && ((MethodContext) current).isInlineFunction()) {
634                    return true;
635                }
636                current = current.getParentContext();
637            }
638            return false;
639        }
640    
641        private boolean isInlineMethodContext() {
642            return this instanceof MethodContext && ((MethodContext) this).isInlineFunction();
643        }
644    }