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;
018    
019    import com.intellij.openapi.util.Pair;
020    import com.intellij.openapi.util.text.StringUtil;
021    import com.intellij.psi.PsiElement;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.codegen.context.*;
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.JvmAbi;
029    import org.jetbrains.kotlin.name.Name;
030    import org.jetbrains.kotlin.psi.*;
031    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
032    import org.jetbrains.kotlin.resolve.BindingContext;
033    import org.jetbrains.kotlin.resolve.DescriptorFactory;
034    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
035    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
036    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
037    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
038    import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
039    import org.jetbrains.kotlin.types.ErrorUtils;
040    import org.jetbrains.kotlin.types.JetType;
041    import org.jetbrains.org.objectweb.asm.FieldVisitor;
042    import org.jetbrains.org.objectweb.asm.MethodVisitor;
043    import org.jetbrains.org.objectweb.asm.Opcodes;
044    import org.jetbrains.org.objectweb.asm.Type;
045    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
046    import org.jetbrains.org.objectweb.asm.commons.Method;
047    
048    import java.util.List;
049    
050    import static org.jetbrains.kotlin.codegen.AsmUtil.*;
051    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface;
052    import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*;
053    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
054    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isTrait;
055    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.PROPERTY_METADATA_TYPE;
056    import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
057    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
058    
059    public class PropertyCodegen {
060        private final GenerationState state;
061        private final ClassBuilder v;
062        private final FunctionCodegen functionCodegen;
063        private final JetTypeMapper typeMapper;
064        private final BindingContext bindingContext;
065        private final FieldOwnerContext context;
066        private final MemberCodegen<?> memberCodegen;
067        private final OwnerKind kind;
068    
069        public PropertyCodegen(
070                @NotNull FieldOwnerContext context,
071                @NotNull ClassBuilder v,
072                @NotNull FunctionCodegen functionCodegen,
073                @NotNull MemberCodegen<?> memberCodegen
074        ) {
075            this.state = functionCodegen.state;
076            this.v = v;
077            this.functionCodegen = functionCodegen;
078            this.typeMapper = state.getTypeMapper();
079            this.bindingContext = state.getBindingContext();
080            this.context = context;
081            this.memberCodegen = memberCodegen;
082            this.kind = context.getContextKind();
083        }
084    
085        public void gen(@NotNull JetProperty property) {
086            VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, property);
087            assert variableDescriptor instanceof PropertyDescriptor : "Property " + property.getText() + " should have a property descriptor: " + variableDescriptor;
088    
089            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
090            gen(property, propertyDescriptor, property.getGetter(), property.getSetter());
091        }
092    
093        public void generateInPackageFacade(@NotNull DeserializedPropertyDescriptor deserializedProperty) {
094            assert context instanceof PackageFacadeContext : "should be called only for generating package facade: " + context;
095            gen(null, deserializedProperty, null, null);
096        }
097    
098        private void gen(
099                @Nullable JetProperty declaration,
100                @NotNull PropertyDescriptor descriptor,
101                @Nullable JetPropertyAccessor getter,
102                @Nullable JetPropertyAccessor setter
103        ) {
104            assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.TRAIT_IMPL
105                    : "Generating property with a wrong kind (" + kind + "): " + descriptor;
106    
107            if (context instanceof PackageFacadeContext) {
108                Type ownerType = ((PackageFacadeContext) context).getDelegateToClassType();
109                v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, descriptor, shortNameByAsmType(ownerType));
110            }
111            else {
112                assert declaration != null : "Declaration is null for different context: " + context;
113                if (!generateBackingField(declaration, descriptor)) {
114                    generateSyntheticMethodIfNeeded(descriptor);
115                }
116            }
117    
118            if (isAccessorNeeded(declaration, descriptor, getter)) {
119                generateGetter(declaration, descriptor, getter);
120            }
121            if (isAccessorNeeded(declaration, descriptor, setter)) {
122                generateSetter(declaration, descriptor, setter);
123            }
124    
125            context.recordSyntheticAccessorIfNeeded(descriptor, bindingContext);
126        }
127    
128        /**
129         * Determines if it's necessary to generate an accessor to the property, i.e. if this property can be referenced via getter/setter
130         * for any reason
131         *
132         * @see JvmCodegenUtil#couldUseDirectAccessToProperty
133         */
134        private boolean isAccessorNeeded(
135                @Nullable JetProperty declaration,
136                @NotNull PropertyDescriptor descriptor,
137                @Nullable JetPropertyAccessor accessor
138        ) {
139            boolean isDefaultAccessor = accessor == null || !accessor.hasBody();
140    
141            // Don't generate accessors for trait properties with default accessors in TRAIT_IMPL
142            if (kind == OwnerKind.TRAIT_IMPL && isDefaultAccessor) return false;
143    
144            if (declaration == null) return true;
145    
146            // Delegated or extension properties can only be referenced via accessors
147            if (declaration.hasDelegate() || declaration.getReceiverTypeReference() != null) return true;
148    
149            // Companion object properties always should have accessors, because their backing fields are moved/copied to the outer class
150            if (isCompanionObject(descriptor.getContainingDeclaration())) return true;
151    
152            // Private class properties have accessors only in cases when those accessors are non-trivial
153            if (kind == OwnerKind.IMPLEMENTATION && Visibilities.isPrivate(descriptor.getVisibility())) {
154                return !isDefaultAccessor;
155            }
156    
157            return true;
158        }
159    
160        public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) {
161            generateBackingField(p, descriptor);
162            if (!Visibilities.isPrivate(descriptor.getVisibility())) {
163                generateGetter(p, descriptor, null);
164                if (descriptor.isVar()) {
165                    generateSetter(p, descriptor, null);
166                }
167            }
168        }
169    
170        public void generateConstructorPropertyAsMethodForAnnotationClass(JetParameter p, PropertyDescriptor descriptor) {
171            JvmMethodSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor);
172            String name = p.getName();
173            if (name == null) return;
174            MethodVisitor mv = v.newMethod(
175                    OtherOrigin(p, descriptor), ACC_PUBLIC | ACC_ABSTRACT, name,
176                    signature.getAsmMethod().getDescriptor(),
177                    signature.getGenericsSignature(),
178                    null
179            );
180    
181            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
182                JetExpression defaultValue = p.getDefaultValue();
183                if (defaultValue != null) {
184                    CompileTimeConstant<?> constant = ExpressionCodegen.getCompileTimeConstant(defaultValue, bindingContext);
185                    assert constant != null : "Default value for annotation parameter should be compile time value: " + defaultValue.getText();
186                    AnnotationCodegen annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(mv, typeMapper);
187                    annotationCodegen.generateAnnotationDefaultValue(constant, descriptor.getType());
188                }
189            }
190    
191            mv.visitEnd();
192        }
193    
194        private boolean generateBackingField(@NotNull JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor) {
195            if (isInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.TRAIT_IMPL) {
196                return false;
197            }
198    
199            if (p instanceof JetProperty && ((JetProperty) p).hasDelegate()) {
200                generatePropertyDelegateAccess((JetProperty) p, descriptor);
201            }
202            else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
203                generateBackingFieldAccess(p, descriptor);
204            }
205            else {
206                return false;
207            }
208            return true;
209        }
210    
211        // Annotations on properties without backing fields are stored in bytecode on an empty synthetic method. This way they're still
212        // accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
213        private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor) {
214            if (descriptor.getAnnotations().isEmpty()) return;
215    
216            ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter();
217            String name = JvmAbi.getSyntheticMethodNameForAnnotatedProperty(descriptor.getName());
218            String desc = receiver == null ? "()V" : "(" + typeMapper.mapType(receiver.getType()) + ")V";
219    
220            if (!isTrait(context.getContextDescriptor()) || kind == OwnerKind.TRAIT_IMPL) {
221                int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
222                MethodVisitor mv = v.newMethod(OtherOrigin(descriptor), flags, name, desc, null, null);
223                AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(descriptor, Type.VOID_TYPE);
224                mv.visitCode();
225                mv.visitInsn(Opcodes.RETURN);
226                mv.visitEnd();
227            }
228            else {
229                Type tImplType = typeMapper.mapTraitImpl((ClassDescriptor) context.getContextDescriptor());
230                v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, descriptor, shortNameByAsmType(tImplType));
231            }
232    
233            if (kind != OwnerKind.TRAIT_IMPL) {
234                v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, new Method(name, desc));
235            }
236        }
237    
238        private void generateBackingField(JetNamedDeclaration element, PropertyDescriptor propertyDescriptor, boolean isDelegate, JetType jetType, Object defaultValue) {
239            int modifiers = getDeprecatedAccessFlag(propertyDescriptor);
240    
241            for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) {
242                if (flagAnnotation.hasAnnotation(propertyDescriptor.getOriginal())) {
243                    modifiers |= flagAnnotation.getJvmFlag();
244                }
245            }
246    
247            if (kind == OwnerKind.PACKAGE) {
248                modifiers |= ACC_STATIC;
249            }
250    
251            if (!propertyDescriptor.isVar() || isDelegate) {
252                modifiers |= ACC_FINAL;
253            }
254    
255            Type type = typeMapper.mapType(jetType);
256    
257            ClassBuilder builder = v;
258    
259            FieldOwnerContext backingFieldContext = context;
260            if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) {
261                modifiers |= ACC_STATIC | getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegate);
262                if (AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) {
263                    ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
264                    builder = codegen.v;
265                    backingFieldContext = codegen.context;
266                    v.getSerializationBindings().put(STATIC_FIELD_IN_OUTER_CLASS, propertyDescriptor);
267                }
268            }
269            else if (kind != OwnerKind.PACKAGE || isDelegate) {
270                modifiers |= ACC_PRIVATE;
271            }
272    
273            if (AsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) {
274                ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
275                parentBodyCodegen.addCompanionObjectPropertyToCopy(propertyDescriptor, defaultValue);
276            }
277    
278            String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate);
279    
280            v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name));
281    
282            FieldVisitor fv = builder.newField(OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(),
283                                                    typeMapper.mapFieldSignature(jetType), defaultValue);
284            AnnotationCodegen.forField(fv, typeMapper).genAnnotations(propertyDescriptor, type);
285        }
286    
287        private void generatePropertyDelegateAccess(JetProperty p, PropertyDescriptor propertyDescriptor) {
288            JetExpression delegateExpression = p.getDelegateExpression();
289            JetType delegateType = delegateExpression != null ? bindingContext.getType(p.getDelegateExpression()) : null;
290            if (delegateType == null) {
291                // If delegate expression is unresolved reference
292                delegateType = ErrorUtils.createErrorType("Delegate type");
293            }
294    
295            generateBackingField(p, propertyDescriptor, true, delegateType, null);
296        }
297    
298        private void generateBackingFieldAccess(JetNamedDeclaration p, PropertyDescriptor propertyDescriptor) {
299            Object value = null;
300    
301            if (shouldWriteFieldInitializer(propertyDescriptor)) {
302                CompileTimeConstant<?> initializer = propertyDescriptor.getCompileTimeInitializer();
303                if (initializer != null) {
304                    value = initializer.getValue();
305                }
306            }
307    
308            generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value);
309        }
310    
311        private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) {
312            //final field of primitive or String type
313            if (!descriptor.isVar()) {
314                Type type = typeMapper.mapType(descriptor);
315                return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName());
316            }
317            return false;
318        }
319    
320        private void generateGetter(@Nullable JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable JetPropertyAccessor getter) {
321            generateAccessor(p, getter, descriptor.getGetter() != null
322                                        ? descriptor.getGetter()
323                                        : DescriptorFactory.createDefaultGetter(descriptor));
324        }
325    
326        private void generateSetter(@Nullable JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor, @Nullable JetPropertyAccessor setter) {
327            if (!descriptor.isVar()) return;
328    
329            generateAccessor(p, setter, descriptor.getSetter() != null
330                                        ? descriptor.getSetter()
331                                        : DescriptorFactory.createDefaultSetter(descriptor));
332        }
333    
334        private void generateAccessor(
335                @Nullable JetNamedDeclaration p,
336                @Nullable JetPropertyAccessor accessor,
337                @NotNull PropertyAccessorDescriptor accessorDescriptor
338        ) {
339            FunctionGenerationStrategy strategy;
340            if (accessor == null || !accessor.hasBody()) {
341                if (p instanceof JetProperty && ((JetProperty) p).hasDelegate()) {
342                    strategy = new DelegatedPropertyAccessorStrategy(state, accessorDescriptor, indexOfDelegatedProperty((JetProperty) p));
343                }
344                else {
345                    strategy = new DefaultPropertyAccessorStrategy(state, accessorDescriptor);
346                }
347            }
348            else {
349                strategy = new FunctionGenerationStrategy.FunctionDefault(state, accessorDescriptor, accessor);
350            }
351    
352            functionCodegen.generateMethod(OtherOrigin(accessor != null ? accessor : p, accessorDescriptor), accessorDescriptor, strategy);
353        }
354    
355        public static int indexOfDelegatedProperty(@NotNull JetProperty property) {
356            PsiElement parent = property.getParent();
357            JetDeclarationContainer container;
358            if (parent instanceof JetClassBody) {
359                container = ((JetClassOrObject) parent.getParent());
360            }
361            else if (parent instanceof JetFile) {
362                container = (JetFile) parent;
363            }
364            else {
365                throw new UnsupportedOperationException("Unknown delegated property container: " + parent);
366            }
367    
368            int index = 0;
369            for (JetDeclaration declaration : container.getDeclarations()) {
370                if (declaration instanceof JetProperty && ((JetProperty) declaration).hasDelegate()) {
371                    if (declaration == property) {
372                        return index;
373                    }
374                    index++;
375                }
376            }
377    
378            throw new IllegalStateException("Delegated property not found in its parent: " + PsiUtilPackage.getElementTextWithContext(property));
379        }
380    
381    
382        private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
383            public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
384                super(state, descriptor);
385            }
386    
387            @Override
388            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
389                InstructionAdapter v = codegen.v;
390                PropertyDescriptor propertyDescriptor = callableDescriptor.getCorrespondingProperty();
391                StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
392    
393                PsiElement jetProperty = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
394                if (jetProperty instanceof JetProperty || jetProperty instanceof JetParameter) {
395                    codegen.markLineNumber((JetElement) jetProperty, false);
396                }
397    
398                if (callableDescriptor instanceof PropertyGetterDescriptor) {
399                    Type type = signature.getReturnType();
400                    property.put(type, v);
401                    v.areturn(type);
402                }
403                else if (callableDescriptor instanceof PropertySetterDescriptor) {
404                    List<ValueParameterDescriptor> valueParameters = callableDescriptor.getValueParameters();
405                    assert valueParameters.size() == 1 : "Property setter should have only one value parameter but has " + callableDescriptor;
406                    int parameterIndex = codegen.lookupLocalIndex(valueParameters.get(0));
407                    assert parameterIndex >= 0 : "Local index for setter parameter should be positive or zero: " + callableDescriptor;
408                    Type type = codegen.typeMapper.mapType(propertyDescriptor);
409                    property.store(StackValue.local(parameterIndex, type), codegen.v);
410                    v.visitInsn(RETURN);
411                }
412                else {
413                    throw new IllegalStateException("Unknown property accessor: " + callableDescriptor);
414                }
415            }
416        }
417    
418        public static StackValue invokeDelegatedPropertyConventionMethod(
419                @NotNull PropertyDescriptor propertyDescriptor,
420                @NotNull ExpressionCodegen codegen,
421                @NotNull JetTypeMapper typeMapper,
422                @NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
423                final int indexInPropertyMetadataArray,
424                int propertyMetadataArgumentIndex
425        ) {
426            CodegenContext<? extends ClassOrPackageFragmentDescriptor> ownerContext = codegen.getContext().getClassOrPackageParentContext();
427            final Type owner;
428            if (ownerContext instanceof ClassContext) {
429                owner = typeMapper.mapClass(((ClassContext) ownerContext).getContextDescriptor());
430            }
431            else if (ownerContext instanceof PackageContext) {
432                owner = ((PackageContext) ownerContext).getPackagePartType();
433            }
434            else {
435                throw new UnsupportedOperationException("Unknown context: " + ownerContext);
436            }
437    
438            codegen.tempVariables.put(
439                    resolvedCall.getCall().getValueArguments().get(propertyMetadataArgumentIndex).asElement(),
440                    new StackValue(PROPERTY_METADATA_TYPE) {
441                        @Override
442                        public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
443                            Field array = StackValue
444                                    .field(Type.getType("[" + PROPERTY_METADATA_TYPE), owner, JvmAbi.PROPERTY_METADATA_ARRAY_NAME, true,
445                                           StackValue.none());
446                            StackValue.arrayElement(PROPERTY_METADATA_TYPE, array, StackValue.constant(indexInPropertyMetadataArray, Type.INT_TYPE)).put(type, v);
447                        }
448                    }
449            );
450    
451            StackValue delegatedProperty = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
452            return codegen.invokeFunction(resolvedCall, delegatedProperty);
453        }
454    
455        private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
456            private final int index;
457    
458            public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor, int index) {
459                super(state, descriptor);
460                this.index = index;
461            }
462    
463            @Override
464            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
465                InstructionAdapter v = codegen.v;
466    
467                BindingContext bindingContext = state.getBindingContext();
468                ResolvedCall<FunctionDescriptor> resolvedCall =
469                        bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, callableDescriptor);
470                assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString();
471    
472                StackValue lastValue = invokeDelegatedPropertyConventionMethod(callableDescriptor.getCorrespondingProperty(),
473                                                                               codegen, state.getTypeMapper(), resolvedCall, index, 1);
474                Type asmType = signature.getReturnType();
475                lastValue.put(asmType, v);
476                v.areturn(asmType);
477            }
478        }
479    
480        @NotNull
481        public static String getterName(Name propertyName) {
482            return JvmAbi.GETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName.asString());
483        }
484    
485        @NotNull
486        public static String setterName(Name propertyName) {
487            return JvmAbi.SETTER_PREFIX + StringUtil.capitalizeWithJavaBeanConvention(propertyName.asString());
488        }
489    
490        public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) {
491            ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration();
492    
493            PropertyGetterDescriptor getter = delegate.getGetter();
494            if (getter != null) {
495                //noinspection ConstantConditions
496                functionCodegen.genDelegate(getter, delegateTo.getGetter().getOriginal(), toClass, field);
497            }
498    
499            PropertySetterDescriptor setter = delegate.getSetter();
500            if (setter != null) {
501                //noinspection ConstantConditions
502                functionCodegen.genDelegate(setter, delegateTo.getSetter().getOriginal(), toClass, field);
503            }
504        }
505    }