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.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.JetTypeMapper;
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.isJvmInterface;
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 public ClassContext intoDefaultImplsClass(ClassDescriptor descriptor, ClassContext interfaceContext, GenerationState state) {
271 return new DefaultImplsClassContext(state.getTypeMapper(), descriptor, OwnerKind.DEFAULT_IMPLS, this, null, interfaceContext);
272 }
273
274 @NotNull
275 public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
276 if (descriptor.isCompanionObject()) {
277 CodegenContext companionContext = this.findChildContext(descriptor);
278 if (companionContext != null) {
279 assert companionContext.getContextKind() == kind : "Kinds should be same, but: " +
280 companionContext.getContextKind() + "!= " + kind;
281 return (ClassContext) companionContext;
282 }
283 }
284 ClassContext classContext = new ClassContext(state.getTypeMapper(), descriptor, kind, this, null);
285
286 if (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);
302 }
303
304 @NotNull
305 public MethodContext intoInlinedLambda(FunctionDescriptor descriptor, boolean isCrossInline) {
306 return new InlineLambdaContext(descriptor, getContextKind(), this, null, isCrossInline);
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 private <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 getAccessorForSuperCallIfNeeded(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
375 if (superCallTarget != null && !isJvmInterface(descriptor.getContainingDeclaration())) {
376 CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext();
377 CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget);
378 assert c != null : "Couldn't find a context for a super-call: " + descriptor;
379 if (c != afterInline.getParentContext()) {
380 return (D) c.getAccessor(descriptor, superCallTarget);
381 }
382 }
383 return descriptor;
384 }
385
386 @NotNull
387 public <D extends CallableMemberDescriptor> D getAccessor(
388 @NotNull D possiblySubstitutedDescriptor,
389 @NotNull FieldAccessorKind accessorKind,
390 @Nullable KotlinType delegateType,
391 @Nullable ClassDescriptor superCallTarget
392 ) {
393 // TODO this corresponds to default behavior for properties before fixing KT-9717. Is it Ok in general case?
394 // Does not matter for other descriptor kinds.
395 return getAccessor(possiblySubstitutedDescriptor, accessorKind, delegateType, superCallTarget,
396 /* getterAccessorRequired */ true,
397 /* setterAccessorRequired */ true);
398 }
399
400 @SuppressWarnings("unchecked")
401 @NotNull
402 private <D extends CallableMemberDescriptor> D getAccessor(
403 @NotNull D possiblySubstitutedDescriptor,
404 @NotNull FieldAccessorKind accessorKind,
405 @Nullable KotlinType delegateType,
406 @Nullable ClassDescriptor superCallTarget,
407 boolean getterAccessorRequired,
408 boolean setterAccessorRequired
409 ) {
410 if (accessors == null) {
411 accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
412 }
413 if (propertyAccessorFactories == null) {
414 propertyAccessorFactories = new LinkedHashMap<AccessorKey, AccessorForPropertyDescriptorFactory>();
415 }
416
417 D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
418 AccessorKey key = new AccessorKey(descriptor, superCallTarget);
419
420 // NB should check for property accessor factory first (or change property accessor tracking under propertyAccessorFactory creation)
421 AccessorForPropertyDescriptorFactory propertyAccessorFactory = propertyAccessorFactories.get(key);
422 if (propertyAccessorFactory != null) {
423 return (D) propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
424 }
425 AccessorForCallableDescriptor<?> accessor = accessors.get(key);
426 if (accessor != null) {
427 assert accessorKind == FieldAccessorKind.NORMAL ||
428 accessor instanceof AccessorForPropertyBackingField : "There is already exists accessor with isForBackingField = false in this context";
429 return (D) accessor;
430 }
431 String nameSuffix = SyntheticAccessorUtilKt.getAccessorNameSuffix(descriptor, key.superCallLabelTarget, accessorKind);
432 if (descriptor instanceof SimpleFunctionDescriptor) {
433 accessor = new AccessorForFunctionDescriptor(
434 (FunctionDescriptor) descriptor, contextDescriptor, superCallTarget, nameSuffix
435 );
436 }
437 else if (descriptor instanceof ConstructorDescriptor) {
438 accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallTarget);
439 }
440 else if (descriptor instanceof PropertyDescriptor) {
441 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
442 switch (accessorKind) {
443 case NORMAL:
444 propertyAccessorFactory = new AccessorForPropertyDescriptorFactory((PropertyDescriptor) descriptor, contextDescriptor,
445 superCallTarget, nameSuffix);
446 propertyAccessorFactories.put(key, propertyAccessorFactory);
447
448 // Record worst case accessor for accessor methods generation.
449 AccessorForPropertyDescriptor accessorWithGetterAndSetter =
450 propertyAccessorFactory.getOrCreateAccessorWithSyntheticGetterAndSetter();
451 accessors.put(key, accessorWithGetterAndSetter);
452
453 PropertyDescriptor accessorDescriptor =
454 propertyAccessorFactory.getOrCreateAccessorIfNeeded(getterAccessorRequired, setterAccessorRequired);
455 return (D) accessorDescriptor;
456 case IN_CLASS_COMPANION:
457 accessor = new AccessorForPropertyBackingFieldInClassCompanion(propertyDescriptor, contextDescriptor,
458 delegateType, nameSuffix);
459 break;
460 case FIELD_FROM_LOCAL:
461 accessor = new AccessorForPropertyBackingFieldFromLocal(propertyDescriptor, contextDescriptor, nameSuffix);
462 break;
463 }
464 }
465 else {
466 throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
467 }
468
469 accessors.put(key, accessor);
470
471 return (D) accessor;
472 }
473
474 @Nullable
475 protected StackValue.Field computeOuterExpression() {
476 return null;
477 }
478
479 public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result, GenerationState state, boolean ignoreNoOuter) {
480 StackValue myOuter = null;
481 if (closure != null) {
482 EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d);
483 if (answer != null) {
484 return StackValue.changeReceiverForFieldAndSharedVar(answer.getInnerValue(), result);
485 }
486
487 for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
488 if (aCase.isCase(d)) {
489 Type classType = state.getTypeMapper().mapType(getThisDescriptor());
490 StackValue.StackValueWithSimpleReceiver innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
491 if (innerValue == null) {
492 break;
493 }
494 else {
495 return StackValue.changeReceiverForFieldAndSharedVar(innerValue, result);
496 }
497 }
498 }
499
500 myOuter = getOuterExpression(result, ignoreNoOuter, false);
501 result = myOuter;
502 }
503
504 StackValue resultValue;
505 if (myOuter != null && getEnclosingClass() == d) {
506 resultValue = result;
507 } else {
508 resultValue = parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null;
509 }
510
511 if (myOuter != null && resultValue != null && !isStaticField(resultValue)) {
512 closure.setCaptureThis();
513 }
514 return resultValue;
515 }
516
517 @NotNull
518 @ReadOnly
519 public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
520 return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
521 }
522
523 @SuppressWarnings("unchecked")
524 @NotNull
525 public <D extends CallableMemberDescriptor> D accessibleDescriptor(
526 @NotNull D descriptor,
527 @Nullable ClassDescriptor superCallTarget
528 ) {
529 CodegenContext properContext = getFirstCrossInlineOrNonInlineContext();
530 DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
531 boolean isInliningContext = properContext.isInlineMethodContext();
532 if (!isInliningContext && (
533 !properContext.hasThisDescriptor() ||
534 enclosing == properContext.getThisDescriptor() ||
535 enclosing == properContext.getClassOrPackageParentContext().getContextDescriptor())) {
536 return descriptor;
537 }
538 return (D) properContext.accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
539 }
540
541 @SuppressWarnings("unchecked")
542 @NotNull
543 private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
544 @NotNull D descriptor,
545 @Nullable ClassDescriptor superCallTarget,
546 boolean withinInliningContext
547 ) {
548 CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
549
550 DeclarationDescriptor enclosed = descriptor.getContainingDeclaration();
551 CodegenContext descriptorContext = findParentContextWithDescriptor(enclosed);
552 if (descriptorContext == null && DescriptorUtils.isCompanionObject(enclosed)) {
553 CodegenContext classContext = findParentContextWithDescriptor(enclosed.getContainingDeclaration());
554 if (classContext instanceof ClassContext) {
555 descriptorContext = ((ClassContext) classContext).getCompanionObjectContext();
556 }
557 }
558
559 if (descriptorContext == null &&
560 JavaVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() &&
561 !(descriptor instanceof SamConstructorDescriptor)) {
562 //seems we need static receiver in resolved call
563 descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
564 superCallTarget = (ClassDescriptor) enclosed;
565 }
566
567 if (descriptorContext == null && withinInliningContext && superCallTarget != null) {
568 //generate super calls within inline function through synthetic accessors
569 descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this);
570 }
571
572 if (descriptorContext == null) {
573 return descriptor;
574 }
575 if (descriptor instanceof PropertyDescriptor) {
576 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
577 int propertyAccessFlag = getVisibilityAccessFlag(descriptor);
578
579 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
580 int getterAccessFlag = getter == null ? propertyAccessFlag
581 : propertyAccessFlag | getVisibilityAccessFlag(getter);
582 boolean getterAccessorRequired = isAccessorRequired(getterAccessFlag, unwrappedDescriptor, descriptorContext,
583 withinInliningContext, superCallTarget != null);
584
585 PropertySetterDescriptor setter = propertyDescriptor.getSetter();
586 int setterAccessFlag = setter == null ? propertyAccessFlag
587 : propertyAccessFlag | getVisibilityAccessFlag(setter);
588 boolean setterAccessorRequired = isAccessorRequired(setterAccessFlag, unwrappedDescriptor, descriptorContext,
589 withinInliningContext, superCallTarget != null);
590
591 if (!getterAccessorRequired && !setterAccessorRequired) {
592 return descriptor;
593 }
594 return (D) descriptorContext.getPropertyAccessor(propertyDescriptor, superCallTarget, getterAccessorRequired, setterAccessorRequired);
595 }
596 else {
597 int flag = getVisibilityAccessFlag(unwrappedDescriptor);
598 if (!isAccessorRequired(flag, unwrappedDescriptor, descriptorContext, withinInliningContext, superCallTarget != null)) {
599 return descriptor;
600 }
601 return (D) descriptorContext.getAccessor(descriptor, superCallTarget);
602 }
603 }
604
605 private static boolean isAccessorRequired(
606 int accessFlag,
607 @NotNull CallableMemberDescriptor unwrappedDescriptor,
608 @NotNull CodegenContext descriptorContext,
609 boolean withinInline,
610 boolean isSuperCall
611 ) {
612 return isSuperCall && withinInline ||
613 (accessFlag & ACC_PRIVATE) != 0 ||
614 ((accessFlag & ACC_PROTECTED) != 0 &&
615 (withinInline || !isInSamePackage(unwrappedDescriptor, descriptorContext.getContextDescriptor())));
616 }
617
618 private static boolean isInSamePackage(DeclarationDescriptor descriptor1, DeclarationDescriptor descriptor2) {
619 PackageFragmentDescriptor package1 =
620 DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor.class, false);
621 PackageFragmentDescriptor package2 =
622 DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor.class, false);
623
624 return package2 != null && package1 != null &&
625 package1.getFqName().equals(package2.getFqName());
626 }
627
628 private void addChild(@NotNull CodegenContext child) {
629 if (shouldAddChild(child)) {
630 if (childContexts == null) {
631 childContexts = new HashMap<DeclarationDescriptor, CodegenContext>();
632 }
633 DeclarationDescriptor childContextDescriptor = child.getContextDescriptor();
634 childContexts.put(childContextDescriptor, child);
635 }
636 }
637
638 protected boolean shouldAddChild(@NotNull CodegenContext child) {
639 return DescriptorUtils.isCompanionObject(child.contextDescriptor);
640 }
641
642 @Nullable
643 protected CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
644 return childContexts == null ? null : childContexts.get(child);
645 }
646
647 private static boolean isStaticField(@NotNull StackValue value) {
648 return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
649 }
650
651 public boolean isInlineMethodContext() {
652 return false;
653 }
654
655 @NotNull
656 public CodegenContext getFirstCrossInlineOrNonInlineContext() {
657 return this;
658 }
659 }