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