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.resolve.annotations.AnnotationUtilKt;
033 import org.jetbrains.kotlin.storage.LockBasedStorageManager;
034 import org.jetbrains.kotlin.storage.NullableLazyValue;
035 import org.jetbrains.kotlin.types.KotlinType;
036 import org.jetbrains.org.objectweb.asm.Type;
037
038 import java.util.*;
039
040 import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityAccessFlag;
041 import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
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 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(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
278 if (descriptor.isCompanionObject()) {
279 CodegenContext companionContext = this.findChildContext(descriptor);
280 if (companionContext != null) {
281 assert companionContext.getContextKind() == kind : "Kinds should be same, but: " +
282 companionContext.getContextKind() + "!= " + kind;
283 return (ClassContext) companionContext;
284 }
285 }
286 ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
287
288 if (descriptor.getCompanionObjectDescriptor() != null) {
289 //We need to create companion object context ahead of time
290 // because otherwise we can't generate synthetic accessor for private members in companion object
291 classContext.intoClass(descriptor.getCompanionObjectDescriptor(), OwnerKind.IMPLEMENTATION, state);
292 }
293 return classContext;
294 }
295
296 @NotNull
297 public ClassContext intoAnonymousClass(@NotNull ClassDescriptor descriptor, @NotNull ExpressionCodegen codegen, @NotNull OwnerKind ownerKind) {
298 return new AnonymousClassContext(codegen.getState().getTypeMapper(), descriptor, ownerKind, this, codegen);
299 }
300
301 @NotNull
302 public MethodContext intoFunction(FunctionDescriptor descriptor) {
303 return new MethodContext(descriptor, getContextKind(), this, null);
304 }
305
306 @NotNull
307 public MethodContext intoInlinedLambda(FunctionDescriptor descriptor, boolean isCrossInline) {
308 return new InlineLambdaContext(descriptor, getContextKind(), this, null, isCrossInline);
309 }
310
311 @NotNull
312 public ConstructorContext intoConstructor(@NotNull ConstructorDescriptor descriptor) {
313 return new ConstructorContext(descriptor, getContextKind(), this, closure);
314 }
315
316 @NotNull
317 public ScriptContext intoScript(
318 @NotNull ScriptDescriptor script,
319 @NotNull List<ScriptDescriptor> earlierScripts,
320 @NotNull ClassDescriptor classDescriptor,
321 @NotNull KotlinTypeMapper typeMapper
322 ) {
323 return new ScriptContext(typeMapper, script, earlierScripts, classDescriptor, this);
324 }
325
326 @NotNull
327 public ClosureContext intoClosure(
328 @NotNull FunctionDescriptor funDescriptor,
329 @NotNull LocalLookup localLookup,
330 @NotNull KotlinTypeMapper typeMapper
331 ) {
332 return new ClosureContext(typeMapper, funDescriptor, this, localLookup);
333 }
334
335 @Nullable
336 public CodegenContext getParentContext() {
337 return parentContext;
338 }
339
340 public ClassDescriptor getEnclosingClass() {
341 CodegenContext cur = getParentContext();
342 while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) {
343 cur = cur.getParentContext();
344 }
345
346 return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor();
347 }
348
349 @Nullable
350 public CodegenContext findParentContextWithDescriptor(DeclarationDescriptor descriptor) {
351 CodegenContext c = this;
352 while (c != null) {
353 if (c.getContextDescriptor() == descriptor) break;
354 c = c.getParentContext();
355 }
356 return c;
357 }
358
359 @NotNull
360 private PropertyDescriptor getPropertyAccessor(
361 @NotNull PropertyDescriptor propertyDescriptor,
362 @Nullable ClassDescriptor superCallTarget,
363 boolean getterAccessorRequired,
364 boolean setterAccessorRequired
365 ) {
366 return getAccessor(propertyDescriptor, FieldAccessorKind.NORMAL, null, superCallTarget, getterAccessorRequired, setterAccessorRequired);
367 }
368
369 @NotNull
370 private <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
371 return getAccessor(descriptor, FieldAccessorKind.NORMAL, null, superCallTarget);
372 }
373
374 @SuppressWarnings("unchecked")
375 @NotNull
376 public <D extends CallableMemberDescriptor> D getAccessorForSuperCallIfNeeded(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
377 if (superCallTarget != null && !isJvmInterface(descriptor.getContainingDeclaration())) {
378 CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext();
379 CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget);
380 assert c != null : "Couldn't find a context for a super-call: " + descriptor;
381 if (c != afterInline.getParentContext()) {
382 return (D) c.getAccessor(descriptor, superCallTarget);
383 }
384 }
385 return descriptor;
386 }
387
388 @NotNull
389 public <D extends CallableMemberDescriptor> D getAccessor(
390 @NotNull D possiblySubstitutedDescriptor,
391 @NotNull FieldAccessorKind accessorKind,
392 @Nullable KotlinType delegateType,
393 @Nullable ClassDescriptor superCallTarget
394 ) {
395 // TODO this corresponds to default behavior for properties before fixing KT-9717. Is it Ok in general case?
396 // Does not matter for other descriptor kinds.
397 return getAccessor(possiblySubstitutedDescriptor, accessorKind, delegateType, superCallTarget,
398 /* getterAccessorRequired */ true,
399 /* setterAccessorRequired */ true);
400 }
401
402 @SuppressWarnings("unchecked")
403 @NotNull
404 private <D extends CallableMemberDescriptor> D getAccessor(
405 @NotNull D possiblySubstitutedDescriptor,
406 @NotNull FieldAccessorKind accessorKind,
407 @Nullable KotlinType delegateType,
408 @Nullable ClassDescriptor superCallTarget,
409 boolean getterAccessorRequired,
410 boolean setterAccessorRequired
411 ) {
412 if (accessors == null) {
413 accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
414 }
415 if (propertyAccessorFactories == null) {
416 propertyAccessorFactories = new LinkedHashMap<AccessorKey, AccessorForPropertyDescriptorFactory>();
417 }
418
419 D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
420 AccessorKey key = new AccessorKey(descriptor, superCallTarget);
421
422 // NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
423 AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key);
424 if (propertyAccessorFactory != null) {
425 return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
426 }
427 AccessorForCallableDescriptor<?> accessor = accessors.get(key);
428 if (accessor != null) {
429 assert accessorKind == FieldAccessorKind.NORMAL ||
430 accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
431 return (D) accessor;
432 }
433 String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
434 if (descriptor instanceof SimpleFunctionDescriptor) {
435 accessor = new AccessorForFunctionDescriptor(
436 (FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix
437 );
438 }
439 else if (descriptor instanceof ConstructorDescriptor) {
440 accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallTarget);
441 }
442 else if (descriptor instanceof PropertyDescriptor) {
443 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
444 switch (accessorKind) {
445 case NORMAL:
446 propertyAccessorFactory = new AccessorForPropertyDescriptorFactory((PropertyDescriptor) descriptor, contextDescriptor,
447 superCallTarget, nameSuffix);
448 propertyAccessorFactories.put(key, propertyAccessorFactory);
449
450 // Record worst case accessor for accessor methods generation.
451 AccessorForPropertyDescriptor accessorWithGetterAndSetter =
452 propertyAccessorFactory.getOrCreateAccessorWithSyntheticGetterAndSetter();
453 accessors.put(key, accessorWithGetterAndSetter);
454
455 PropertyDescriptor accessorDescriptor =
456 propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
457 return (D) accessorDescriptor;
458 case IN_CLASS_COMPANION:
459 accessor = new AccessorForPropertyBackingFieldInClassCompanion(propertyDescriptor, contextDescriptor,
460 delegateType, nameSuffix);
461 break;
462 case FIELD_FROM_LOCAL:
463 accessor = new AccessorForPropertyBackingFieldFromLocal(propertyDescriptor, contextDescriptor, nameSuffix);
464 break;
465 }
466 }
467 else {
468 throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
469 }
470
471 accessors.put(key, accessor);
472
473 return (D) accessor;
474 }
475
476 @Nullable
477 protected StackValue.Field computeOuterExpression() {
478 return null;
479 }
480
481 public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
482 StackValue myOuter = null;
483 if (closure != null) {
484 EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
485 if (answer != null) {
486 return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result);
487 }
488
489 for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
490 if (aCase.isCase(d)) {
491 Type classType = state.getTypeMapper().mapType(getThisDescriptor());
492 StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
493 if (innerValue == null) {
494 break;
495 }
496 else {
497 return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
498 }
499 }
500 }
501
502 myOuter = getOuterExpression(result, ignoreNoOuter, false);
503 result = myOuter;
504 }
505
506 StackValue resultValue;
507 if (myOuter != null && getEnclosingClass() == d) {
508 resultValue = result;
509 } else {
510 resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
511 }
512
513 if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
514 closure.setCaptureThis();
515 }
516 return resultValue;
517 }
518
519 @NotNull
520 @ReadOnly
521 public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
522 return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
523 }
524
525 @SuppressWarnings("unchecked")
526 @NotNull
527 public <D extends CallableMemberDescriptor> D accessibleDescriptor(
528 @NotNull D descriptor,
529 @Nullable ClassDescriptor superCallTarget
530 ) {
531 CodegenContext properContext = getFirstCrossInlineOrNonInlineContext();
532 DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
533 boolean isInliningContext = properContext.isInlineMethodContext();
534 if (!isInliningContext && (
535 !properContext.hasThisDescriptor() ||
536 enclosing == properContext.getThisDescriptor() ||
537 enclosing == properContext.getClassOrPackageParentContext().getContextDescriptor())) {
538 return descriptor;
539 }
540 return (D) properContext.accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
541 }
542
543 @SuppressWarnings("unchecked")
544 @NotNull
545 private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
546 @NotNull D descriptor,
547 @Nullable ClassDescriptor superCallTarget,
548 boolean withinInliningContext
549 ) {
550 CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
551
552 DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
553 CodegenContext descriptorContext = findParentContextWithDescriptor(enclosed);
554 if (descriptorContext == null && DescriptorUtils.isCompanionObject(enclosed)) {
555 CodegenContext classContext = findParentContextWithDescriptor(enclosed.getContainingDeclaration());
556 if (classContext instanceof ClassContext) {
557 descriptorContext = ((ClassContext) classContext).getCompanionObjectContext();
558 }
559 }
560
561 if (descriptorContext == null &&
562 JavaVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() &&
563 !(descriptor instanceof SamConstructorDescriptor)) {
564 //seems we need static receiver in resolved call
565 descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
566 superCallTarget = (ClassDescriptor) enclosed;
567 }
568
569 if (descriptorContext == null && withinInliningContext && superCallTarget != null) {
570 //generate super calls within inline function through synthetic accessors
571 descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
572 }
573
574 if (descriptorContext == null) {
575 return descriptor;
576 }
577 if (descriptor instanceof PropertyDescriptor) {
578 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
579 int propertyAccessFlag = getVisibilityAccessFlag(descriptor);
580
581 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
582 int getterAccessFlag = getter == null ? propertyAccessFlag
583 : propertyAccessFlag | getVisibilityAccessFlag(getter);
584 boolean getterAccessorRequired = isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext,
585 withinInliningContext, superCallTarget != null);
586
587 PropertySetterDescriptor setter = propertyDescriptor.getSetter();
588
589 int setterAccessFlag = propertyAccessFlag;
590 if (setter != null && setter.getVisibility().normalize() != Visibilities.INVISIBLE_FAKE) {
591 setterAccessFlag = propertyAccessFlag | getVisibilityAccessFlag(setter);
592 }
593 boolean setterAccessorRequired = isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext,
594 withinInliningContext, superCallTarget != null);
595
596 if (!getterAccessorRequired && !setterAccessorRequired) {
597 return descriptor;
598 }
599 return (D) descriptorContext.getPropertyAccessor(propertyDescriptor, superCallTarget, getterAccessorRequired, setterAccessorRequired);
600 }
601 else {
602 int flag = getVisibilityAccessFlag(unwrappedDescriptor);
603 if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext, withinInliningContext, superCallTarget != null)) {
604 return descriptor;
605 }
606 return (D) descriptorContext.getAccessor(descriptor, superCallTarget);
607 }
608 }
609
610 private static boolean isAccessorRequired(
611 int accessFlag,
612 @NotNull CallableMemberDescriptor unwrappedDescriptor,
613 @NotNull CodegenContext descriptorContext,
614 boolean withinInline,
615 boolean isSuperCall
616 ) {
617 if (AnnotationUtilKt.isInlineOnlyOrReified(unwrappedDescriptor)) return false;
618
619 return isSuperCall && withinInline ||
620 (accessFlag & ACC_PRIVATE) != 0 ||
621 ((accessFlag & ACC_PROTECTED) != 0 &&
622 (withinInline || !isInSamePackage(unwrappedDescriptor, descriptorContext.getContextDescriptor())));
623 }
624
625 private static boolean isInSamePackage(DeclarationDescriptor descriptor1, DeclarationDescriptor descriptor2) {
626 PackageFragmentDescriptor package1 =
627 DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor.class, false);
628 PackageFragmentDescriptor package2 =
629 DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor.class, false);
630
631 return package2 != null && package1 != null &&
632 package1.getFqName().equals(package2.getFqName());
633 }
634
635 private void addChild(@NotNull CodegenContext child) {
636 if (shouldAddChild(child)) {
637 if (childContexts == null) {
638 childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
639 }
640 DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
641 childContexts.put(childContextDescriptor, child);
642 }
643 }
644
645 protected boolean shouldAddChild(@NotNull CodegenContext child) {
646 return DescriptorUtils.isCompanionObject(child.contextDescriptor);
647 }
648
649 @Nullable
650 protected CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
651 return childContexts == null ? null : childContexts.get(child);
652 }
653
654 private static boolean isStaticField(@NotNull StackValue value) {
655 return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
656 }
657
658 public boolean isInlineMethodContext() {
659 return false;
660 }
661
662 @NotNull
663 public CodegenContext getFirstCrossInlineOrNonInlineContext() {
664 return this;
665 }
666 }