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