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 }