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;
018    
019    import com.intellij.openapi.util.Pair;
020    import com.intellij.psi.PsiElement;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
024    import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations;
025    import org.jetbrains.kotlin.codegen.context.*;
026    import org.jetbrains.kotlin.codegen.state.GenerationState;
027    import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
028    import org.jetbrains.kotlin.descriptors.*;
029    import org.jetbrains.kotlin.descriptors.annotations.Annotated;
030    import org.jetbrains.kotlin.descriptors.annotations.AnnotationSplitter;
031    import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
032    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
033    import org.jetbrains.kotlin.fileClasses.JvmFileClassUtilKt;
034    import org.jetbrains.kotlin.load.java.JvmAbi;
035    import org.jetbrains.kotlin.psi.*;
036    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
037    import org.jetbrains.kotlin.resolve.BindingContext;
038    import org.jetbrains.kotlin.resolve.DescriptorFactory;
039    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
040    import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
041    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
042    import org.jetbrains.kotlin.resolve.constants.ConstantValue;
043    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
044    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
045    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
046    import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
047    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
048    import org.jetbrains.kotlin.types.ErrorUtils;
049    import org.jetbrains.kotlin.types.KotlinType;
050    import org.jetbrains.org.objectweb.asm.FieldVisitor;
051    import org.jetbrains.org.objectweb.asm.MethodVisitor;
052    import org.jetbrains.org.objectweb.asm.Opcodes;
053    import org.jetbrains.org.objectweb.asm.Type;
054    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
055    import org.jetbrains.org.objectweb.asm.commons.Method;
056    
057    import java.util.List;
058    
059    import static org.jetbrains.kotlin.codegen.AsmUtil.getDeprecatedAccessFlag;
060    import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityForBackingField;
061    import static org.jetbrains.kotlin.codegen.AsmUtil.isPropertyWithBackingFieldCopyInOuterClass;
062    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
063    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
064    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
065    import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY;
066    import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY;
067    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
068    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
069    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.K_PROPERTY_TYPE;
070    import static org.jetbrains.kotlin.resolve.jvm.annotations.AnnotationUtilKt.hasJvmFieldAnnotation;
071    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
072    
073    public class PropertyCodegen {
074        private final GenerationState state;
075        private final ClassBuilder v;
076        private final FunctionCodegen functionCodegen;
077        private final KotlinTypeMapper typeMapper;
078        private final BindingContext bindingContext;
079        private final FieldOwnerContext context;
080        private final MemberCodegen<?> memberCodegen;
081        private final OwnerKind kind;
082    
083        public PropertyCodegen(
084                @NotNull FieldOwnerContext context,
085                @NotNull ClassBuilder v,
086                @NotNull FunctionCodegen functionCodegen,
087                @NotNull MemberCodegen<?> memberCodegen
088        ) {
089            this.state = functionCodegen.state;
090            this.v = v;
091            this.functionCodegen = functionCodegen;
092            this.typeMapper = state.getTypeMapper();
093            this.bindingContext = state.getBindingContext();
094            this.context = context;
095            this.memberCodegen = memberCodegen;
096            this.kind = context.getContextKind();
097        }
098    
099        public void gen(@NotNull KtProperty property) {
100            VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, property);
101            if (!(variableDescriptor instanceof PropertyDescriptor)) {
102                throw ExceptionLogger.logDescriptorNotFound(
103                        "Property " + property.getName() + " should have a property descriptor: " + variableDescriptor, property
104                );
105            }
106    
107            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
108            gen(property, propertyDescriptor, property.getGetter(), property.getSetter());
109        }
110    
111        public void generateInPackageFacade(@NotNull DeserializedPropertyDescriptor deserializedProperty) {
112            assert context instanceof MultifileClassFacadeContext : "should be called only for generating facade: " + context;
113            gen(null, deserializedProperty, null, null);
114        }
115    
116        private void gen(
117                @Nullable KtProperty declaration,
118                @NotNull PropertyDescriptor descriptor,
119                @Nullable KtPropertyAccessor getter,
120                @Nullable KtPropertyAccessor setter
121        ) {
122            assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DEFAULT_IMPLS
123                    : "Generating property with a wrong kind (" + kind + "): " + descriptor;
124    
125            genBackingFieldAndAnnotations(declaration, descriptor, false);
126    
127            if (isAccessorNeeded(declaration, descriptor, getter)) {
128                generateGetter(declaration, descriptor, getter);
129            }
130            if (isAccessorNeeded(declaration, descriptor, setter)) {
131                generateSetter(declaration, descriptor, setter);
132            }
133        }
134    
135        private void genBackingFieldAndAnnotations(
136                @Nullable KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter
137        ) {
138            boolean hasBackingField = hasBackingField(descriptor);
139            boolean hasDelegate = declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate();
140    
141            AnnotationSplitter annotationSplitter =
142                    AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS,
143                                              descriptor.getAnnotations(),
144                                              AnnotationSplitter.getTargetSet(isParameter, descriptor.isVar(), hasBackingField, hasDelegate));
145    
146            Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
147    
148            // Fields and '$annotations' methods for non-private const properties are generated in the multi-file facade
149            boolean isBackingFieldOwner = descriptor.isConst() && !Visibilities.isPrivate(descriptor.getVisibility())
150                                          ? !(context instanceof MultifileClassPartContext)
151                                          : CodegenContextUtil.isImplClassOwner(context);
152    
153            if (isBackingFieldOwner) {
154                Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
155                Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD);
156                assert declaration != null : "Declaration is null: " + descriptor + " (context=" + context + ")";
157                generateBackingField(declaration, descriptor, fieldAnnotations, delegateAnnotations);
158                generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations);
159            }
160    
161            if (!propertyAnnotations.getAllAnnotations().isEmpty() && kind != OwnerKind.DEFAULT_IMPLS &&
162                CodegenContextUtil.isImplClassOwner(context)) {
163                v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, getSyntheticMethodSignature(descriptor));
164            }
165        }
166    
167        /**
168         * Determines if it's necessary to generate an accessor to the property, i.e. if this property can be referenced via getter/setter
169         * for any reason
170         *
171         * @see JvmCodegenUtil#couldUseDirectAccessToProperty
172         */
173        private boolean isAccessorNeeded(
174                @Nullable KtProperty declaration,
175                @NotNull PropertyDescriptor descriptor,
176                @Nullable KtPropertyAccessor accessor
177        ) {
178            if (isConstOrHasJvmFieldAnnotation(descriptor)) return false;
179    
180            boolean isDefaultAccessor = accessor == null || !accessor.hasBody();
181    
182            // Don't generate accessors for interface properties with default accessors in DefaultImpls
183            if (kind == OwnerKind.DEFAULT_IMPLS && isDefaultAccessor) return false;
184    
185            if (declaration == null) return true;
186    
187            // Delegated or extension properties can only be referenced via accessors
188            if (declaration.hasDelegate() || declaration.getReceiverTypeReference() != null) return true;
189    
190            // Companion object properties always should have accessors, because their backing fields are moved/copied to the outer class
191            if (isCompanionObject(descriptor.getContainingDeclaration())) return true;
192    
193            // Non-const properties from multifile classes have accessors regardless of visibility
194            if (!descriptor.isConst() && JvmFileClassUtilKt.isInsideJvmMultifileClassFile(declaration)) return true;
195    
196            // Private class properties have accessors only in cases when those accessors are non-trivial
197            if (Visibilities.isPrivate(descriptor.getVisibility())) {
198                return !isDefaultAccessor;
199            }
200    
201            return true;
202        }
203    
204        private static boolean areAccessorsNeededForPrimaryConstructorProperty(
205                @NotNull PropertyDescriptor descriptor
206        ) {
207            if (hasJvmFieldAnnotation(descriptor)) return false;
208    
209            return !Visibilities.isPrivate(descriptor.getVisibility());
210        }
211    
212        public void generatePrimaryConstructorProperty(@NotNull KtParameter p, @NotNull PropertyDescriptor descriptor) {
213            genBackingFieldAndAnnotations(p, descriptor, true);
214    
215            if (areAccessorsNeededForPrimaryConstructorProperty(descriptor)) {
216                generateGetter(p, descriptor, null);
217                generateSetter(p, descriptor, null);
218            }
219        }
220    
221        public void generateConstructorPropertyAsMethodForAnnotationClass(KtParameter p, PropertyDescriptor descriptor) {
222            JvmMethodGenericSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor);
223            String name = p.getName();
224            if (name == null) return;
225            MethodVisitor mv = v.newMethod(
226                    JvmDeclarationOriginKt.OtherOrigin(p, descriptor), ACC_PUBLIC | ACC_ABSTRACT, name,
227                    signature.getAsmMethod().getDescriptor(),
228                    signature.getGenericsSignature(),
229                    null
230            );
231    
232            KtExpression defaultValue = p.getDefaultValue();
233            if (defaultValue != null) {
234                ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(
235                        defaultValue, bindingContext, true, state.getShouldInlineConstVals());
236                assert !state.getClassBuilderMode().generateBodies || constant != null
237                        : "Default value for annotation parameter should be compile time value: " + defaultValue.getText();
238                if (constant != null) {
239                    AnnotationCodegen annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(mv, memberCodegen, typeMapper);
240                    annotationCodegen.generateAnnotationDefaultValue(constant, descriptor.getType());
241                }
242            }
243    
244            mv.visitEnd();
245        }
246    
247        private boolean hasBackingField(@NotNull PropertyDescriptor descriptor) {
248            return !isJvmInterface(descriptor.getContainingDeclaration()) &&
249                   kind != OwnerKind.DEFAULT_IMPLS &&
250                   !Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor));
251        }
252    
253        private boolean generateBackingField(
254                @NotNull KtNamedDeclaration p,
255                @NotNull PropertyDescriptor descriptor,
256                @NotNull Annotations backingFieldAnnotations,
257                @NotNull Annotations delegateAnnotations
258        ) {
259            if (isJvmInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.DEFAULT_IMPLS) {
260                return false;
261            }
262    
263            if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
264                generatePropertyDelegateAccess((KtProperty) p, descriptor, delegateAnnotations);
265            }
266            else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
267                generateBackingFieldAccess(p, descriptor, backingFieldAnnotations);
268            }
269            else {
270                return false;
271            }
272            return true;
273        }
274    
275        // Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still
276        // accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
277        private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, @NotNull Annotations annotations) {
278            if (annotations.getAllAnnotations().isEmpty()) return;
279    
280            DeclarationDescriptor contextDescriptor = context.getContextDescriptor();
281            if (!isInterface(contextDescriptor) ||
282                (FunctionCodegen.processInterface(contextDescriptor, kind, state) ||
283                 (kind == OwnerKind.DEFAULT_IMPLS && state.getGenerateDefaultImplsForJvm8()))) {
284                int flags = ACC_DEPRECATED | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
285                Method syntheticMethod = getSyntheticMethodSignature(descriptor);
286                MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
287                                               syntheticMethod.getDescriptor(), null, null);
288                AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper)
289                        .genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
290                mv.visitCode();
291                mv.visitInsn(Opcodes.RETURN);
292                mv.visitEnd();
293            }
294        }
295    
296        @NotNull
297        private Method getSyntheticMethodSignature(@NotNull PropertyDescriptor descriptor) {
298            ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter();
299            String name = JvmAbi.getSyntheticMethodNameForAnnotatedProperty(descriptor.getName());
300            String desc = receiver == null ? "()V" : "(" + typeMapper.mapType(receiver.getType()) + ")V";
301            return new Method(name, desc);
302        }
303    
304        private void generateBackingField(
305                KtNamedDeclaration element,
306                PropertyDescriptor propertyDescriptor,
307                boolean isDelegate,
308                KotlinType kotlinType,
309                Object defaultValue,
310                Annotations annotations
311        ) {
312            int modifiers = getDeprecatedAccessFlag(propertyDescriptor);
313    
314            for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) {
315                if (flagAnnotation.hasAnnotation(propertyDescriptor.getOriginal())) {
316                    modifiers |= flagAnnotation.getJvmFlag();
317                }
318            }
319    
320            if (kind == OwnerKind.PACKAGE) {
321                modifiers |= ACC_STATIC;
322            }
323    
324            if (!propertyDescriptor.isLateInit() && (!propertyDescriptor.isVar() || isDelegate)) {
325                modifiers |= ACC_FINAL;
326            }
327    
328            if (AnnotationUtilKt.hasJvmSyntheticAnnotation(propertyDescriptor)) {
329                modifiers |= ACC_SYNTHETIC;
330            }
331    
332            Type type = typeMapper.mapType(kotlinType);
333    
334            ClassBuilder builder = v;
335    
336            FieldOwnerContext backingFieldContext = context;
337            if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) {
338                modifiers |= ACC_STATIC;
339    
340                if (JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) {
341                    ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
342                    builder = codegen.v;
343                    backingFieldContext = codegen.context;
344                }
345            }
346            modifiers |= getVisibilityForBackingField(propertyDescriptor, isDelegate);
347    
348            if (AsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) {
349                ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
350                parentBodyCodegen.addCompanionObjectPropertyToCopy(propertyDescriptor, defaultValue);
351            }
352    
353            String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate);
354    
355            v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name));
356    
357            FieldVisitor fv = builder.newField(
358                    JvmDeclarationOriginKt.OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(),
359                    isDelegate ? null : typeMapper.mapFieldSignature(kotlinType, propertyDescriptor), defaultValue
360            );
361    
362            Annotated fieldAnnotated = new AnnotatedWithFakeAnnotations(propertyDescriptor, annotations);
363            AnnotationCodegen.forField(fv, memberCodegen, typeMapper).genAnnotations(
364                    fieldAnnotated, type, isDelegate ? AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD : AnnotationUseSiteTarget.FIELD);
365        }
366    
367        private void generatePropertyDelegateAccess(
368                @NotNull KtProperty p,
369                @NotNull PropertyDescriptor propertyDescriptor,
370                @NotNull Annotations annotations
371        ) {
372            KotlinType delegateType = getDelegateTypeForProperty(p, propertyDescriptor);
373    
374            generateBackingField(p, propertyDescriptor, true, delegateType, null, annotations);
375        }
376    
377        @NotNull
378        private KotlinType getDelegateTypeForProperty(@NotNull KtProperty p, @NotNull PropertyDescriptor propertyDescriptor) {
379            KotlinType delegateType = null;
380    
381            ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall =
382                    bindingContext.get(BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor);
383            KtExpression delegateExpression = p.getDelegateExpression();
384    
385            if (provideDelegateResolvedCall != null) {
386                delegateType = provideDelegateResolvedCall.getResultingDescriptor().getReturnType();
387            }
388            else if (delegateExpression != null) {
389                delegateType = bindingContext.getType(delegateExpression);
390            }
391    
392            if (delegateType == null) {
393                // Delegation convention is unresolved
394                delegateType = ErrorUtils.createErrorType("Delegate type");
395            }
396            return delegateType;
397        }
398    
399        private void generateBackingFieldAccess(
400                @NotNull KtNamedDeclaration p,
401                @NotNull PropertyDescriptor propertyDescriptor,
402                @NotNull Annotations annotations
403        ) {
404            Object value = null;
405    
406            if (shouldWriteFieldInitializer(propertyDescriptor)) {
407                ConstantValue<?> initializer = propertyDescriptor.getCompileTimeInitializer();
408                if (initializer != null) {
409                    value = initializer.getValue();
410                }
411            }
412    
413            generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations);
414        }
415    
416        private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) {
417            //final field of primitive or String type
418            if (!descriptor.isVar()) {
419                Type type = typeMapper.mapType(descriptor);
420                return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName());
421            }
422            return false;
423        }
424    
425        private void generateGetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor getter) {
426            generateAccessor(p, getter, descriptor.getGetter() != null
427                                        ? descriptor.getGetter()
428                                        : DescriptorFactory.createDefaultGetter(descriptor, Annotations.Companion.getEMPTY()));
429        }
430    
431        private void generateSetter(@Nullable KtNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor setter) {
432            if (!descriptor.isVar()) return;
433    
434            generateAccessor(p, setter, descriptor.getSetter() != null
435                                        ? descriptor.getSetter()
436                                        : DescriptorFactory.createDefaultSetter(descriptor, Annotations.Companion.getEMPTY()));
437        }
438    
439        private void generateAccessor(
440                @Nullable KtNamedDeclaration p,
441                @Nullable KtPropertyAccessor accessor,
442                @NotNull PropertyAccessorDescriptor accessorDescriptor
443        ) {
444            if (context instanceof MultifileClassFacadeContext &&
445                (Visibilities.isPrivate(accessorDescriptor.getVisibility()) ||
446                 AsmUtil.getVisibilityAccessFlag(accessorDescriptor) == Opcodes.ACC_PRIVATE)) {
447                return;
448            }
449    
450            FunctionGenerationStrategy strategy;
451            if (accessor == null || !accessor.hasBody()) {
452                if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
453                    strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor, indexOfDelegatedProperty((KtProperty) p));
454                }
455                else {
456                    strategy = new DefaultPropertyAccessorStrategy(state, accessorDescriptor);
457                }
458            }
459            else {
460                strategy = new FunctionGenerationStrategy.FunctionDefault(state, accessor);
461            }
462    
463            functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(accessor != null ? accessor : p, accessorDescriptor), accessorDescriptor, strategy);
464        }
465    
466        public static int indexOfDelegatedProperty(@NotNull KtProperty property) {
467            PsiElement parent = property.getParent();
468            KtDeclarationContainer container;
469            if (parent instanceof KtClassBody) {
470                container = ((KtClassOrObject) parent.getParent());
471            }
472            else if (parent instanceof KtFile) {
473                container = (KtFile) parent;
474            }
475            else if (KtPsiUtil.isScriptDeclaration(property)) {
476                container = KtPsiUtil.getScript(property);
477                assert  container != null : "Script declaration for property '" + property.getText() + "' should be not null!";
478            }
479            else {
480                throw new UnsupportedOperationException("Unknown delegated property container: " + parent);
481            }
482    
483            int index = 0;
484            for (KtDeclaration declaration : container.getDeclarations()) {
485                if (declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate()) {
486                    if (declaration == property) {
487                        return index;
488                    }
489                    index++;
490                }
491            }
492    
493            throw new IllegalStateException("Delegated property not found in its parent: " + PsiUtilsKt.getElementTextWithContext(property));
494        }
495    
496    
497        private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
498            private final PropertyAccessorDescriptor propertyAccessorDescriptor;
499            public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
500                super(state);
501                propertyAccessorDescriptor = descriptor;
502            }
503    
504            @Override
505            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
506                InstructionAdapter v = codegen.v;
507                PropertyDescriptor propertyDescriptor = propertyAccessorDescriptor.getCorrespondingProperty();
508                StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
509    
510                PsiElement jetProperty = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
511                if (jetProperty instanceof KtProperty || jetProperty instanceof KtParameter) {
512                    codegen.markLineNumber((KtElement) jetProperty, false);
513                }
514    
515                if (propertyAccessorDescriptor instanceof PropertyGetterDescriptor) {
516                    Type type = signature.getReturnType();
517                    property.put(type, v);
518                    v.areturn(type);
519                }
520                else if (propertyAccessorDescriptor instanceof PropertySetterDescriptor) {
521                    List<ValueParameterDescriptor> valueParameters = propertyAccessorDescriptor.getValueParameters();
522                    assert valueParameters.size() == 1 : "Property setter should have only one value parameter but has " + propertyAccessorDescriptor;
523                    int parameterIndex = codegen.lookupLocalIndex(valueParameters.get(0));
524                    assert parameterIndex >= 0 : "Local index for setter parameter should be positive or zero: " + propertyAccessorDescriptor;
525                    Type type = codegen.typeMapper.mapType(propertyDescriptor);
526                    property.store(StackValue.local(parameterIndex, type), codegen.v);
527                    v.visitInsn(RETURN);
528                }
529                else {
530                    throw new IllegalStateException("Unknown property accessor: " + propertyAccessorDescriptor);
531                }
532            }
533        }
534    
535        public static StackValue invokeDelegatedPropertyConventionMethod(
536                @NotNull PropertyDescriptor propertyDescriptor,
537                @NotNull ExpressionCodegen codegen,
538                @NotNull KotlinTypeMapper typeMapper,
539                @NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
540                final int indexInPropertyMetadataArray,
541                int propertyMetadataArgumentIndex
542        ) {
543            StackValue.Property receiver = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
544            return invokeDelegatedPropertyConventionMethodWithReceiver(
545                    codegen, typeMapper, resolvedCall, indexInPropertyMetadataArray, propertyMetadataArgumentIndex,
546                    receiver, propertyDescriptor
547            );
548        }
549    
550        public static StackValue invokeDelegatedPropertyConventionMethodWithReceiver(
551                @NotNull ExpressionCodegen codegen,
552                @NotNull KotlinTypeMapper typeMapper,
553                @NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
554                final int indexInPropertyMetadataArray,
555                int propertyMetadataArgumentIndex,
556                @Nullable StackValue receiver,
557                @NotNull PropertyDescriptor propertyDescriptor
558        ) {
559            final Type owner = JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor) ?
560                               codegen.getState().getTypeMapper().mapOwner(propertyDescriptor)  :
561                               getDelegatedPropertyMetadataOwner(codegen, typeMapper);
562    
563            codegen.tempVariables.put(
564                    resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
565                    new StackValue(K_PROPERTY_TYPE) {
566                        @Override
567                        public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
568                            Field array = StackValue.field(
569                                    Type.getType("[" + K_PROPERTY_TYPE), owner, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, true, StackValue.none()
570                            );
571                            StackValue.arrayElement(
572                                    K_PROPERTY_TYPE, array, StackValue.constant(indexInPropertyMetadataArray, Type.INT_TYPE)
573                            ).put(type, v);
574                        }
575                    }
576            );
577    
578            return codegen.invokeFunction(resolvedCall, receiver);
579        }
580    
581        private static Type getDelegatedPropertyMetadataOwner(@NotNull ExpressionCodegen codegen, @NotNull KotlinTypeMapper typeMapper) {
582            CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
583            if (ownerContext instanceof ClassContext) {
584                return typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor());
585            }
586            else if (ownerContext instanceof PackageContext) {
587                return ((PackageContext) ownerContext).getPackagePartType();
588            }
589            else if (ownerContext instanceof MultifileClassContextBase) {
590                return ((MultifileClassContextBase) ownerContext).getFilePartType();
591            }
592            else {
593                throw new UnsupportedOperationException("Unknown context: " + ownerContext);
594            }
595        }
596    
597        private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
598            private final int index;
599            private final PropertyAccessorDescriptor propertyAccessorDescriptor;
600    
601            public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor, int index) {
602                super(state);
603                this.index = index;
604                propertyAccessorDescriptor = descriptor;
605            }
606    
607            @Override
608            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
609                InstructionAdapter v = codegen.v;
610    
611                BindingContext bindingContext = state.getBindingContext();
612                ResolvedCall<FunctionDescriptor> resolvedCall =
613                        bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, propertyAccessorDescriptor);
614                assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString();
615    
616                StackValue lastValue = invokeDelegatedPropertyConventionMethod(propertyAccessorDescriptor.getCorrespondingProperty(),
617                                                                               codegen, state.getTypeMapper(), resolvedCall, index, 1);
618                Type asmType = signature.getReturnType();
619                lastValue.put(asmType, v);
620                v.areturn(asmType);
621            }
622        }
623    
624        public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) {
625            ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration();
626    
627            PropertyGetterDescriptor getter = delegate.getGetter();
628            if (getter != null) {
629                //noinspection ConstantConditions
630                functionCodegen.genDelegate(getter, delegateTo.getGetter().getOriginal(), toClass, field);
631            }
632    
633            PropertySetterDescriptor setter = delegate.getSetter();
634            if (setter != null) {
635                //noinspection ConstantConditions
636                functionCodegen.genDelegate(setter, delegateTo.getSetter().getOriginal(), toClass, field);
637            }
638        }
639    }